# Lista de pacotes necessários
packages <- c(
  "dplyr", "ggplot2", "corrplot", "car", "lubridate",
  "tidyr", "stringr", "stringi", "rstatix", "sf",
  "purrr", "GGally", "FactoMineR", "factoextra",
  "patchwork", "mice", "janitor", "scales", "trend"
)

# Instalar apenas os que não estão instalados
installed <- packages %in% rownames(installed.packages())
if (any(!installed)) {
  install.packages(packages[!installed])
}

library(dplyr)
library(ggplot2)
library(corrplot)
library(car)
library(lubridate)
library(tidyr)
library(stringr)
library(stringi)
library(rstatix)
library(sf)
library(purrr)
library(GGally)
library(FactoMineR)
library(factoextra)
library(patchwork)
library(mice)
library(janitor)
library(scales)
library(trend)

#ler data
hypertension <- read.csv2("https://transparencia.sns.gov.pt/api/explore/v2.1/catalog/datasets/hipertensao/exports/csv?lang=pt&timezone=Europe%2FLisbon")
avc <- read.csv2("https://transparencia.sns.gov.pt/api/explore/v2.1/catalog/datasets/evolucao-situacoes-doentes-sinais-sintomas-de-avc/exports/csv?lang=pt&timezone=Europe%2FLondon&use_labels=true&delimiter=%3B")

## Vamos primeiro analisar o dataset hypertension:

#Ver missing values 

out <- sapply(hypertension, function(x) sum(is.na(x) | x == ""))
       
#no dataframe de hipertensão existem 24 missing values na variavel ponto_ou_localizacao_geografica.
#Retiro as observações ou faço imputação? Tenho de ver se é relevante também


#avaliar relevância da variável
#ver relevância da localização para os valores de hipertenção
# Modelo completo - regressão de poisson (variável é uma contagem)
modelo_completo <- glm(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~ 
    ponto_ou_localizacao_geografica + regiao + tempo, data = hypertension)

# Modelo sem ponto_ou_localizacao_geografica
modelo_reduzido <- glm(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~ 
    regiao + tempo, data = hypertension)

# Teste de razão de verossimilhança
anova(modelo_reduzido, modelo_completo, test = "Chisq")
Analysis of Deviance Table

Model 1: contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~ 
    regiao + tempo
Model 2: contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~ 
    ponto_ou_localizacao_geografica + regiao + tempo
  Resid. Df Resid. Dev  Df   Deviance  Pr(>Chi)    
1      6432 4.4253e+10                             
2      6317 1.0484e+10 115 3.3769e+10 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#variável relevante


total_data <-  length(hypertension$ponto_ou_localizacao_geografica)
percentage_null <- 100*as.numeric(out["ponto_ou_localizacao_geografica"])/total_data

#percentagem de missing values é 0.3659 - muito pequena logo em princípio pode ser aceitável remove-las


#ver distribuição temporal dos valores sem localização correspondente e respetiva percentagem
where_na <- hypertension %>%
  filter(ponto_ou_localizacao_geografica == "" | is.na (ponto_ou_localizacao_geografica)) %>%
  count(tempo, name = "ausentes")

total_period <- hypertension %>%
  count(tempo, name = "total")

percentages <- left_join(where_na, total_period, by = "tempo") %>%
  mutate(percentagem = round((ausentes / total) * 100, 2))

#a percentagem sobe 5.13% , criando duvidas sobre a remoção

#comportamento dos valores sem localização correspondente
# Adiciona uma flag para missing ou não
hypertension$localizacao <- ifelse(hypertension$ponto_ou_localizacao_geografica == "" | is.na(hypertension$ponto_ou_localizacao_geografica), FALSE, TRUE)

# Compara as médias e medianas
# total de dados
metrica_total <- hypertension %>%
     summarise(across(where(is.numeric), list(media = mean, mediana = median, variancia = var), na.rm = TRUE))
 
# dados com localização
metrica_com_local <- hypertension %>%
     filter(localizacao != FALSE) %>%
     summarise(across(where(is.numeric), list(media = mean, mediana = median, variancia = var), na.rm = TRUE))

#os valores das métricas comparadas não são muito discrepantes logo concluimos que a melhor abordagem é a imputação porque os dados sem localização representam a amostra, a que é confirmado pelo Welch Two Sample t-test
amostra1 <- hypertension$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
amostra2 <- hypertension %>%
  filter(localizacao != FALSE) %>%
  pull(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)

t.test(amostra1, amostra2, var.equal = FALSE)

    Welch Two Sample t-test

data:  amostra1 and amostra2
t = 0.45892, df = 13093, p-value = 0.6463
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -96.10491 154.86345
sample estimates:
mean of x mean of y 
 4945.170  4915.791 
# p-value= 0.6463 > 0.05 , não rejeitamos a hipotese nula. Concluímos que não há diferença significativa entre as médias.
# tornar index da localização mais acessivel para que a imputação possa fazer mais sentido
# Renomear a coluna de coordenadas
hypertension <- hypertension %>%
  rename(coords = ponto_ou_localizacao_geografica)

# Separar coordenadas em lat/lon
# Separar a coluna de coordenadas em latitude e longitude

hyp_coords <- hypertension %>%
  separate(coords, into = c("lat", "lon"), sep = ",", convert = TRUE) %>%
  mutate(
    lat = as.numeric(str_replace(lat, ",", ".")),
    lon = as.numeric(str_replace(lon, ",", ".")),
    proporcao_hipertensos_65_a_com_pa_150_90 = as.numeric(proporcao_hipertensos_65_a_com_pa_150_90)
  )
Warning: Expected 2 pieces. Missing pieces filled with `NA` in 24 rows [1244, 1248, 1253, 1286, 1322,
2503, 2521, 2529, 2537, 2545, 2572, 3880, 3909, 3914, 5207, 5225, 5250, 5262, 5277, 5286, ...].
# Garantir que a proporção esteja em formato numérico
hyp_coords <- hyp_coords %>%
  mutate(proporcao_hipertensos_65_a_com_pa_150_90 = as.numeric(proporcao_hipertensos_65_a_com_pa_150_90))


# Converter para sf
hyp_sf <- hyp_coords %>%
  mutate(geometry = pmap(list(lon, lat), function(x, y) {
    if (is.na(x) || is.na(y)) {
      st_geometrycollection()
    } else {
      st_point(c(x, y))
    }
  })) %>%
  st_as_sf(crs = 4326)
# ----------------------------------
# 4. Carregar shapefiles (níveis 2)
# ----------------------------------

# Municípios (Nível 2)
municipios <- st_read("gadm41_PRT_2.shp") %>% st_transform(4326)
Reading layer `gadm41_PRT_2' from data source 
  `/Users/marianahenriques/Documents/ProjetoBioEst/gadm41_PRT_shp/gadm41_PRT_2.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 308 features and 13 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -31.26819 ymin: 30.03018 xmax: -6.189142 ymax: 42.15432
Geodetic CRS:  WGS 84
municipios <- municipios %>%
  rename(distritos = NAME_1,
         municipio = NAME_2)

# ----------------------------------
# 5. Join espacial: Hipertensão → Município
# ----------------------------------

hyper_joined <- st_join(hyp_sf, municipios, join = st_within)
#imputacao com base na semelhança de valores

# Calcular a média por grupo municipio
mean_per_group <- hyper_joined %>%
  filter(!is.na(municipio)) %>%
  group_by(municipio) %>%
  summarise(mean_contagem = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
  st_set_geometry(NULL)

desvio <- hyper_joined %>%
  filter(!is.na(municipio)) %>%
  group_by(municipio) %>%
  summarise(desvio_contagem = sd(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = FALSE)) %>%
  st_set_geometry(NULL)


intervalo <- mean_per_group %>%
  left_join(desvio, by = "municipio") %>%
  mutate(
    limite_inferior = mean_contagem - desvio_contagem,
    limite_superior = mean_contagem + desvio_contagem
  )

# Imputar municipio com base na média mais próxima da contagem
hyp_final <- hyper_joined %>%
  rowwise() %>%
  mutate(municipio = if_else(
    is.na(municipio),
    {
      cont_val <- contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
      
      # Verifica quais municípios têm o valor dentro do intervalo
      dentro_intervalo <- intervalo %>%
        filter(cont_val >= limite_inferior & cont_val <= limite_superior)

      if (nrow(dentro_intervalo) > 0) {
        # Entre os válidos, pega o de média mais próxima
        diffs <- abs(dentro_intervalo$mean_contagem - cont_val)
        dentro_intervalo$municipio[which.min(diffs)]
      } else {
        NA_character_
      }
    },
    municipio
  )) %>%
  ungroup()%>%
  filter(!is.na(municipio))



tabela_correspondencia <- municipios %>%
  st_drop_geometry() %>%
  select(distritos, municipio) %>%
  distinct()

hyp_final <- hyp_final %>%
  mutate(municipio_clean = stri_trans_general(tolower(trimws(municipio)), "Latin-ASCII"))

tabela_correspondencia <- tabela_correspondencia %>%
  mutate(municipio_clean = stri_trans_general(tolower(trimws(municipio)), "Latin-ASCII"))

# 2. Faz o join com base na versão limpa
hyp_final <- hyp_final %>%
  left_join(tabela_correspondencia %>% select(municipio_clean, distritos), by = "municipio_clean")

# --- Efeito da imputação na média ---
# 1. Média original por grupo
mean_attr <- hyper_joined %>%
  filter(!is.na(municipio)) %>%
  group_by(municipio) %>%
  summarise(mean_original = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
  st_set_geometry(NULL)

# 2. Média após imputação (em hyp_final)
mean_per_group_com_imp <- hyp_final %>%
  group_by(municipio) %>%
  summarise(mean_imputada = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
  st_set_geometry(NULL)

# 3. Juntar médias original e imputada
means <- left_join(mean_attr, mean_per_group_com_imp, by = "municipio")

# 4. Gráfico das médias
means_long <- means %>%
  pivot_longer(cols = c(mean_original, mean_imputada),
               names_to = "tipo_media",
               values_to = "media")

grafico <- ggplot(means_long, aes(x = municipio, y = media, fill = tipo_media)) +
  geom_col(position = "dodge") +
  labs(title = "Comparação das médias por municipio",
       x = "Municipio", y = "Média da contagem",
       fill = "Tipo de Média") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggsave(filename = "grafico_medias_por_grupo.png", plot = grafico, width = 10, height = 6, dpi = 300)


# 5. Distância entre valor imputado e média original do grupo
distance <- hyp_final %>%
  filter(localizacao == FALSE) %>%
  st_set_geometry(NULL) %>%
  left_join(mean_attr, by = "municipio") %>%
  mutate(dist = mean_original - contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)

# 6. Gráfico de linhas para analisar 5.
# Criar limites para a região sombreada (banda de confiança)
distance <- distance %>%
  mutate(
    ymin = mean_original - abs(dist),
    ymax = mean_original + abs(dist)
  )

grafico_2 <- ggplot(distance, aes(x = reorder(municipio, mean_original), y = mean_original, group = 1)) +
  geom_ribbon(aes(ymin = ymin, ymax = ymax), fill = "lightblue", alpha = 0.4) +  # região sombreada
  geom_line(color = "blue", size = 1) +  # linha da média
  geom_point(aes(y = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n),
             color = "red", size = 2) +  # pontos do valor imputado
  labs(
    x = "Municípios com valores imputados",
    y = "Valor",
    title = "Média original vs distância do valor imputado",
    subtitle = "Linha azul: média original; Região azul clara: distância; Pontos vermelhos: valores imputados"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

ggsave(filename = "grafico_distancias_por_grupo.png", plot = grafico_2, width = 10, height = 6, dpi = 300)

# --- Comparação da distribuição regional: imputados vs reais ---
tabela_comparativa <- hyp_final %>%
  mutate(tipo = ifelse(localizacao, "Real", "Imputado")) %>%
  group_by(municipio, tipo) %>%
  summarise(total = n(), .groups = "drop") %>%
  group_by(tipo) %>%
  mutate(prop = total / sum(total))

p <- ggplot(tabela_comparativa, aes(x = prop, y = municipio, fill = tipo)) +
  geom_col(position = "dodge") +
  theme_minimal() +
  labs(title = "Distribuição de Municípios: Real vs Imputado",
       y = "Município", x = "Proporção") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

ggsave("grafico_distribuicao.png", plot = p, width = 10, height = 8, dpi = 300)

# --- Correlação ---
cor_before <- cor(
  hyper_joined$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
  hyper_joined$proporcao_hipertensos_65_a_com_pa_150_90,
  use = "complete.obs"
)

cor_after <- cor(
  hyp_final$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
  hyp_final$proporcao_hipertensos_65_a_com_pa_150_90
)

cat("Correlação antes da imputação:", cor_before, "\n")
Correlação antes da imputação: 0.7432419 
cat("Correlação depois da imputação:", cor_after, "\n")
Correlação depois da imputação: 0.7427319 
#summary
summary(hyper_joined %>% select(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, proporcao_hipertensos_65_a_com_pa_150_90))
 contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
 Min.   :  129                                                                                       
 1st Qu.: 2273                                                                                       
 Median : 4117                                                                                       
 Mean   : 4945                                                                                       
 3rd Qu.: 6630                                                                                       
 Max.   :43441                                                                                       
 proporcao_hipertensos_65_a_com_pa_150_90               geometry   
 Min.   : 1.32                            GEOMETRYCOLLECTION:  24  
 1st Qu.:18.07                            POINT             :6536  
 Median :29.83                            epsg:4326         :   0  
 Mean   :31.99                            +proj=long...     :   0  
 3rd Qu.:43.24                                                     
 Max.   :81.75                                                     
summary(hyp_final %>% select(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, proporcao_hipertensos_65_a_com_pa_150_90))
 contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
 Min.   :  129                                                                                       
 1st Qu.: 2272                                                                                       
 Median : 4115                                                                                       
 Mean   : 4935                                                                                       
 3rd Qu.: 6627                                                                                       
 Max.   :43441                                                                                       
 proporcao_hipertensos_65_a_com_pa_150_90               geometry   
 Min.   : 1.32                            GEOMETRYCOLLECTION:  20  
 1st Qu.:18.07                            POINT             :6536  
 Median :29.82                            epsg:4326         :   0  
 Mean   :31.97                            +proj=long...     :   0  
 3rd Qu.:43.18                                                     
 Max.   :81.75                                                     
# --- Dispersão das variáveis principais ---
ggplot(hyp_final, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
                      y = proporcao_hipertensos_65_a_com_pa_150_90,
                      color = localizacao)) +
  geom_point() +
  labs(title = "Correlação: Reais vs Imputados", color = "Dados reais?")


# --- PCA para visualização multivariada ---
dados_pca <- st_drop_geometry(hyp_final[, c("contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n","proporcao_hipertensos_65_a_com_pa_150_90")])

res.pca <- PCA(dados_pca, graph = FALSE)
fviz_pca_ind(res.pca, 
             habillage = as.factor(hyp_final$localizacao),
             title = "PCA: Imputed vs Real Data",
             palette = c("red", "blue"))  # Vermelho = imputado, Azul = real



ggplot(hyper_joined, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)) +
  geom_histogram(bins = 30, fill = "blue", alpha = 0.5) + ggtitle("Contagem Antes da Imputação")


ggplot(hyp_final, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)) +
  geom_histogram(bins = 30, fill = "green", alpha = 0.5) + ggtitle("Contagem Depois da Imputação")


ggplot(hyper_joined, aes(x = proporcao_hipertensos_65_a_com_pa_150_90)) +
  geom_histogram(bins = 30, fill = "blue", alpha = 0.5) + ggtitle("Proporção Antes da Imputação")


ggplot(hyp_final, aes(x = proporcao_hipertensos_65_a_com_pa_150_90)) +
  geom_histogram(bins = 30, fill = "green", alpha = 0.5) + ggtitle("Proporção Depois da Imputação")




#imputação com sucesso

#Analise temporal do dataframe da hipertensao com imputacao

# Calcular proporção total
hyp_final <- hyp_final %>%
  mutate(total = 100 * contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n / proporcao_hipertensos_65_a_com_pa_150_90)

# Total por ano (todos os utentes)
hipertensao_ano <- hyp_final %>%
  mutate(Ano = year(ym(tempo))) %>%
  group_by(Ano) %>%
  summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
  st_set_geometry(NULL)

ggplot(hipertensao_ano, aes(x = factor(Ano), y = total)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = round(total)), vjust = -0.25, size = 3) +
  labs(title = "Total de Utentes com Hipertensão por Ano",
       x = "Ano",
       y = "Total de Utentes") +
  theme_minimal()


# Total por ano para pessoas com menos de 65 anos
hipertensao_ano_menos_65 <- hyp_final %>%
  mutate(Ano = year(ym(tempo))) %>%
  group_by(Ano) %>%
  summarise(hip_menos_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
  st_set_geometry(NULL)

ggplot(hipertensao_ano_menos_65, aes(x = factor(Ano), y = hip_menos_65)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = round(hip_menos_65)), vjust = -0.25, size = 3) +
  labs(title = "Total de Utentes com menos de 65 anos com Hipertensão por Ano",
       x = "Ano",
       y = "Total de Utentes") +
  theme_minimal()


# Comparação entre menos de 65 e 65 ou mais
hipertensao_comp_ano <- hipertensao_ano %>%
  left_join(hipertensao_ano_menos_65, by = "Ano") %>%
  mutate(
    hip_menos_65 = ifelse(is.na(hip_menos_65), 0, hip_menos_65),
    hip_mais_65 = total - hip_menos_65
  ) %>%
  select(Ano, hip_menos_65, hip_mais_65) %>%
  pivot_longer(
    cols = c(hip_menos_65, hip_mais_65),
    names_to = "Group",
    values_to = "total"
  ) %>%
  mutate(
    Group = dplyr::recode(Group,
                          "hip_menos_65" = "Under 65 years old",
                          "hip_mais_65" = "65 years or older")
  )

# Gráfico empilhado
ggplot(hipertensao_comp_ano, aes(x = factor(Ano), y = total, fill = Group)) +
  geom_col() +
  labs(
    title = " Controlled Hypertension by Age and Year",
    x = "Year",
    y = "Number of Patients"
  ) +
  theme_minimal()




# Hipertensão por mês - Total
hipertensao_mes <- hyp_final %>%
  mutate(Data = ym(tempo),
         Mes = month(Data, label = TRUE, abbr = FALSE)) %>%  
  group_by(Mes) %>%
  summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
  arrange(match(Mes, month.name)) %>%
  st_set_geometry(NULL)

ggplot(hipertensao_mes, aes(x = Mes, y = total)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = round(total)), vjust = -0.25, size = 3) +
  labs(title = "Total de Utentes com Hipertensão por Mês",
       x = "Mês",
       y = "Total de Utentes") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))



# Hipertensão por mês - Menos de 65
hipertensao_mes_65 <- hyp_final %>%
  mutate(Data_65 = ym(tempo),
         Mes_65 = month(Data_65, label = TRUE, abbr = FALSE)) %>%  
  group_by(Mes_65) %>%
  summarise(hip_menos_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
  arrange(match(Mes_65, month.name)) %>%
  st_set_geometry(NULL)

ggplot(hipertensao_mes_65, aes(x = Mes_65, y = hip_menos_65)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = round(hip_menos_65)), vjust = -0.25, size = 3) +
  labs(title = "Utentes <65 anos com Hipertensão por Mês",
       x = "Mês",
       y = "Total de Utentes") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))



# Tabela de meses em português
meses_pt <- c("janeiro", "fevereiro", "março", "abril", "maio", "junho", 
              "julho", "agosto", "setembro", "outubro", "novembro", "dezembro")


mes_lookup <- c(
  "january" = "janeiro", "february" = "fevereiro", "march" = "março",
  "april" = "abril", "may" = "maio", "june" = "junho",
  "july" = "julho", "august" = "agosto", "september" = "setembro",
  "october" = "outubro", "november" = "novembro", "december" = "dezembro"
)


# Juntar total e <65, calcular >=65
hipertensao_comp_mes <- hipertensao_mes %>%
  left_join(hipertensao_mes_65, by = c("Mes" = "Mes_65")) %>%
  mutate(
    hip_menos_65 = ifelse(is.na(hip_menos_65), 0, hip_menos_65),
    hip_mais_65 = total - hip_menos_65,
    Mes = dplyr::recode(tolower(as.character(Mes)), !!!mes_lookup),
    Mes = factor(Mes, levels = meses_pt)
  ) %>%
  select(Mes, hip_menos_65, hip_mais_65) %>%
  pivot_longer(
    cols = c(hip_menos_65, hip_mais_65),
    names_to = "Group",
    values_to = "Total_hip"
  ) %>%
  mutate(
    Group = dplyr::recode(Group,
                          "hip_menos_65" = "Under 65 years old",
                          "hip_mais_65" = "65 years or older")
  )

# Gráfico final - barras egroup_by()# Gráfico final - barras empilhadas
ggplot(hipertensao_comp_mes, aes(x = Mes, y = Total_hip, fill = Group)) +
  geom_col() +
  labs(
    title = " Controlled Hypertension by Age and Month",
    x = "Month",
    y = "Number of patients"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))


## Análise do dataset avc: 

#Quais os anos e meses é que estão registados no AVC
meses_por_ano_avc <- avc %>%
  mutate(Ano_avc = year(ym(Período)),
         Mes_avc = month(ym(Período), label = TRUE, abbr = FALSE)) %>%
  distinct(Ano_avc, Mes_avc) %>%
  arrange(Ano_avc, Mes_avc) %>%
  group_by(Ano_avc) %>%
  summarise(Meses_Disponiveis = paste(Mes_avc, collapse = ", "))

#Ver missing values 
sapply(avc, function(x) sum(is.na(x) | x == ""))
                 N.º.Registos                       Período        Distrito.da.Ocorrência 
                            0                             0                             0 
       Concelho.da.Ocorrência        Faixa.Etária.da.Vítima              Género.da.Vítima 
                            0                             0                             0 
          Hospital.de.Destino N.º.de.registos.Via.Verde.AVC 
                            0                             0 
# Distribuição por Género com AVC 

avc_genero <- avc %>%
  group_by(Género.da.Vítima) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
  arrange(desc(Total_AVC))

ggplot(avc_genero, aes(x = reorder(Género.da.Vítima, -Total_AVC), y = Total_AVC, fill = Género.da.Vítima)) +
  geom_col() +
  geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
  labs(title = "Total de Registos de AVC por Género",
       x = "Género",
       y = "Total de AVC") +
  theme_minimal()


# Distribuição por Género com AVC em cada ano

avc_genero_ano <- avc %>%
  mutate(Ano = year(ym(Período))) %>%
  group_by(Ano, Género.da.Vítima) %>%
  summarise(Total_AVC = sum(as.numeric(N.º.de.registos.Via.Verde.AVC), na.rm = TRUE), .groups = "drop")

# Traduzir valores de 'Género.da.Vítima'
avc$Género.da.Vítima <- ifelse(avc$Género.da.Vítima == "Feminino", "Female",
                               ifelse(avc$Género.da.Vítima == "Masculino", "Male", avc$Género.da.Vítima))

ggplot(avc_genero_ano, aes(x = factor(Ano), y = Total_AVC, fill = Género.da.Vítima)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = Total_AVC), position = position_dodge(width = 0.9), vjust = -0.25, size = 3) +
  labs(title = "Total Stroke Records by Year and Gender",
       x = "Year",
       y = "Total Stroke Records",
       fill = "Gender") +
  theme_minimal()



# Distribuição por Género com AVC em cada mês
avc_genero_mes <- avc %>%
  mutate(Mes_Ano = format(ym(Período), "%Y-%m")) %>%
  group_by(Mes_Ano, `Género.da.Vítima`) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop")

ggplot(avc_genero_mes, aes(x = Mes_Ano, y = Total_AVC, fill = `Género.da.Vítima`)) +
  geom_col(position = "dodge") +
  labs(title = "Stroke Distribution by Month and Gender",
       x = "Month", y = "Total Stroke Records", fill = "Gender") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# Distribuição Faixa Etária com AVC no total dos anos

# Define the correct order of age ranges
faixa_ordem <- c("0 - 17", "18 - 29", "30 - 39", "40 - 49", "50 - 59", 
                 "60 - 69", "70 - 79", "80 - 89", "90 - 99", ">100")

# Apply the order using factor
avc_idade <- avc %>%
  group_by(`Faixa.Etária.da.Vítima`) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
  mutate(`Faixa.Etária.da.Vítima` = factor(`Faixa.Etária.da.Vítima`, levels = faixa_ordem)) %>%
  arrange(`Faixa.Etária.da.Vítima`)

# Plot
ggplot(avc_idade, aes(x = `Faixa.Etária.da.Vítima`, y = Total_AVC)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
  labs(title = "Total de Registos de AVC por Faixa Etária",
       x = "Faixa Etária",
       y = "Total de AVC") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# Distribuição Faixa Etária com AVC em cada ano

avc_faixa_ano <- avc %>%
  mutate(Ano = year(ym(Período))) %>%
  group_by(Ano, `Faixa.Etária.da.Vítima`) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop") %>% mutate(`Faixa.Etária.da.Vítima` = factor(`Faixa.Etária.da.Vítima`, levels = faixa_ordem)) %>%
  arrange(`Faixa.Etária.da.Vítima`)


ggplot(avc_faixa_ano, aes(x = factor(Ano), y = Total_AVC, fill = `Faixa.Etária.da.Vítima`)) +
  geom_col(position = "dodge") +
  labs(title = "Total Stroke Records by Year and Age Group",
       x = "Year",
       y = "Total Stroke Records",
       fill = "Age Group") +
  theme_minimal()


# Distribuição Faixa Etária com AVC em cada mês

avc_faixa_mes <- avc %>%
  mutate(Mes_Ano = format(ym(Período), "%Y-%m")) %>%
  group_by(Mes_Ano, `Faixa.Etária.da.Vítima`) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop") %>% mutate(`Faixa.Etária.da.Vítima` = factor(`Faixa.Etária.da.Vítima`, levels = faixa_ordem)) %>%
  arrange(`Faixa.Etária.da.Vítima`)

ggplot(avc_faixa_mes, aes(x = Mes_Ano, y = Total_AVC, fill = `Faixa.Etária.da.Vítima`)) +
  geom_col(position = "dodge") +
  labs(title = "Stroke Distribution by Month and Age Group",
       x = "Month", y = "Total Stroke Records", fill = "Age Groupe") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# Género × Faixa Etária ao longos do período 

avc_cross <- avc %>%
  group_by(`Género.da.Vítima`, `Faixa.Etária.da.Vítima`) %>%
  summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
  ungroup() %>% mutate(`Faixa.Etária.da.Vítima` = factor(`Faixa.Etária.da.Vítima`, levels = faixa_ordem)) %>%
  arrange(`Faixa.Etária.da.Vítima`)
`summarise()` has grouped output by 'Género.da.Vítima'. You can override using the `.groups`
argument.
ggplot(avc_cross, aes(x = `Faixa.Etária.da.Vítima`, y = Total_AVC, fill = `Género.da.Vítima`)) +
  geom_col(position = "dodge") +
  labs(title = "Distribuição de AVC por Género e Faixa Etária", x = "Faixa Etária", y = "Total de AVC", fill = "Género") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Correlação entre Hipertensos e AVC por grupo etário (maiores de 65 anos e menores de 65 anos)

# Clean names
avc <- avc %>% janitor::clean_names()

# Fix column name
names(avc)[names(avc) == "n_o_de_registos_via_verde_avc"] <- "n_de_registos_via_verde_avc"

# Dividimos o AVC em maiores de 65 anos e menores de 65 anos
avc_clean <- avc %>%
  mutate(
    faixa_inicio = as.numeric(str_extract(faixa_etaria_da_vitima, "^\\d+")),
    faixa_fim = as.numeric(str_extract(faixa_etaria_da_vitima, "\\d+$")),
    Group = case_when(
      faixa_inicio < 69 ~ "Under 65 years old",
      TRUE ~ "65 years or older"
    ),
    mes_num = as.integer(str_sub(periodo, 6, 7)),
    mes = factor(meses_pt[mes_num], levels = meses_pt),
    n_de_registos_via_verde_avc = as.numeric(n_de_registos_via_verde_avc)
  ) %>%
  group_by(mes, Group) %>%
  summarise(total_avc = sum(n_de_registos_via_verde_avc, na.rm = TRUE), .groups = "drop")

# Filtrar dados de hipertensão de 2022-01 a 2024-02
hyp_filtrado <- hyp_final %>%
  st_set_geometry(NULL) %>%
  mutate(Data = ym(tempo)) %>%
  filter(Data >= ym("2022-01") & Data <= ym("2024-02"))

# Hipertensão total por mês
hipertensao_mes_filtrado <- hyp_filtrado %>%
  mutate(Mes = month(Data, label = TRUE, abbr = FALSE)) %>%
  group_by(Mes) %>%
  summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
  arrange(match(Mes, month.name))

# Hipertensão em menores de 65 anos
hipertensao_mes_65_filtrado <- hyp_filtrado %>%
  mutate(Mes = month(Data, label = TRUE, abbr = FALSE)) %>%
  group_by(Mes) %>%
  summarise(hip_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
  arrange(match(Mes, month.name))

# Combinar dados de hipertensão e preparar formato longo
hipertensao_comp_mes_filtrado <- hipertensao_mes_filtrado %>%
  left_join(hipertensao_mes_65_filtrado, by = "Mes") %>%
  mutate(
    hip_65 = ifelse(is.na(hip_65), 0, hip_65),
    hip_mais_65 = total - hip_65,
    Mes = mes_lookup[Mes],
    Mes = factor(Mes, levels = meses_pt)
  ) %>%
  select(Mes, hip_65, hip_mais_65) %>%
  pivot_longer(
    cols = c("hip_65", "hip_mais_65"),
    names_to = "Group",
    values_to = "Total_hip"
  ) %>%
  mutate(
    Group = dplyr::recode(Group,
      "hip_65" = "Under 65 years old",
      "hip_mais_65" = "65 years or older")
  )

# Gráfico empilhado de hipertensão
ggplot(hipertensao_comp_mes_filtrado, aes(x = Mes, y = Total_hip, fill = Group)) +
  geom_col() +
  labs(
    title = "Hipertensão por Idade e Mês (2022-01 a 2024-02)",
    x = "Mês",
    y = "Número de Utentes"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))


# Resumo para análise
hipertensao_summary <- hipertensao_comp_mes_filtrado %>%
  group_by(Mes, Group) %>%
  summarise(Total_HIP = sum(Total_hip), .groups = "drop") %>%
  rename(mes = Mes)

# Merge com dados de AVC
merged <- left_join(hipertensao_summary, avc_clean, by = c("mes", "Group"))

# Boxplots para visualização de outliers
ggplot(merged, aes(x = Group, y = Total_HIP)) +
  geom_boxplot() +
  labs(title = "Boxplot of Controlled Hypertension by Age Group", x="Group", y="Total Hypertension Patients")


ggplot(merged, aes(x = Group, y = total_avc)) +
  geom_boxplot() +
  labs(title = "Boxplot of Stroke Cases by Age Group", x="Group", y="Total Stroke Cases")


#como há outliers, fazemos com o spearman

# Correlação de Spearman
cor_results_spearman <- merged %>%
  group_by(Group) %>%
  summarise(correl = cor(Total_HIP, total_avc, method = "spearman"))

print(cor_results_spearman)

# Scatterplot com regressão para visualização
ggplot(merged, aes(x = Total_HIP, y = total_avc, color = Group)) +
  geom_point(size = 3) +
  geom_smooth(method = "lm", se = FALSE) +
  facet_wrap(~ Group) +
  labs(
    title = "Correlation between Controlled Hypertension and Stroke by Age Group",
    x = "Total Hypertension Patients",
    y = "Total Stroke Cases"
  ) +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

# Regressões lineares por grupo
models <- merged %>%
  group_by(Group) %>%
  group_map(~ lm(total_avc ~ Total_HIP, data = .x), .keep = TRUE)

# Resumo das regressões
summary(models[[1]])  # Under 65 years old

Call:
lm(formula = total_avc ~ Total_HIP, data = .x)

Residuals:
    Min      1Q  Median      3Q     Max 
-152.51  -36.62   16.85   56.54  106.31 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 4.703e+02  7.398e+01   6.357 8.28e-05 ***
Total_HIP   3.116e-04  5.918e-05   5.266 0.000365 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 82.79 on 10 degrees of freedom
Multiple R-squared:  0.735, Adjusted R-squared:  0.7085 
F-statistic: 27.73 on 1 and 10 DF,  p-value: 0.0003649
summary(models[[2]])  # 65 years or older

Call:
lm(formula = total_avc ~ Total_HIP, data = .x)

Residuals:
   Min     1Q Median     3Q    Max 
-83.16 -29.66 -13.39  10.95 148.96 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.935e+02  5.092e+01   9.691 2.12e-06 ***
Total_HIP   -1.397e-04  8.325e-05  -1.679    0.124    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 64.71 on 10 degrees of freedom
Multiple R-squared:  0.2198,    Adjusted R-squared:  0.1418 
F-statistic: 2.817 on 1 and 10 DF,  p-value: 0.1242

# Total de Registos de AVC por Distrito
avc_regiao <- avc %>%
  group_by(`distrito_da_ocorrencia`) %>%
  summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE)) %>%
  arrange(desc(Total_AVC)) 

ggplot(avc_regiao, aes(x = reorder(`distrito_da_ocorrencia`, -Total_AVC), y = Total_AVC)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
  labs(title = "Total Stroke Records by District",
       x = "District", y = "Patients") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# Distribuição ao longo do tempo por distrito

avc_regiao_tempo <- avc %>%
  mutate(Mes_Ano = format(ym(periodo), "%Y-%m")) %>%
  group_by(Mes_Ano, `distrito_da_ocorrencia`) %>%
  summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE), .groups = "drop")

ggplot(avc_regiao_tempo, aes(x = Mes_Ano, y = Total_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
  geom_line() +
  labs(title = "Evolução Mensal de Registos de AVC por Distrito",
       x = "Mês", y = "Total de AVC", color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


## Ir buscar o número de habitantes por distrito em portugal em 2022, 2023 e 2024 e fazer média, para normalizar e poder comparar, porque obviamente que no porto e lisboa há maior numero de avc porque há mais habitantes.

# Vetor com as populações médias estimadas
populacao_distritos <- c(
  "Lisboa" = 2318952,
  "Porto" = 1829758,
  "Setúbal" = 893464,
  "Braga" = 858708,
  "Aveiro" = 717998,
  "Faro" = 474500,
  "Leiria" = 471570,
  "Santarém" = 436891,
  "Coimbra" = 413225,
  "Viseu" = 364020,
  "Madeira" = 254630,
  "Açores" = 241471,
  "Viana do Castelo" = 233610,
  "Vila Real" = 185263,
  "Castelo Branco" = 178860,
  "Évora" = 153427,
  "Beja" = 147363,
  "Guarda" = 142131,
  "Bragança" = 123109,
  "Portalegre" = 104561
)


# Adicionar população ao DataFrame
avc_regiao_tempo <- avc_regiao_tempo %>%
  mutate(Populacao = populacao_distritos[`distrito_da_ocorrencia`],
         Taxa_AVC = (Total_AVC / Populacao) * 100000)

# Média da taxa de AVC por distrito
ranking_distritos <- avc_regiao_tempo %>%
  group_by(`distrito_da_ocorrencia`) %>%
  summarise(Media_Taxa_AVC = mean(Taxa_AVC, na.rm = TRUE)) %>%
  arrange(desc(Media_Taxa_AVC))

print(ranking_distritos)

ggplot(ranking_distritos, aes(x = reorder(`distrito_da_ocorrencia`, Media_Taxa_AVC), y = Media_Taxa_AVC)) +
  geom_col(fill = "darkred") +
  geom_text(aes(label = round(Media_Taxa_AVC, 1)), hjust = -0.1, size = 3) +
  coord_flip() +
  labs(title = "Stroke Rate by District",
       x = "District", y = "Rate") +
  theme_minimal()


# Visualizar as taxas de AVC ao longo do tempo por distrito
ggplot(avc_regiao_tempo, aes(x = Mes_Ano, y = Taxa_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
  geom_line() +
  labs(title = "Evolução Mensal da Taxa de AVC por Distrito",
       x = "Mês", y = "Taxa de AVC por 100.000 habitantes", color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


#Como não é possivel comparar bem pelo gráfico, vamos fazer testes estatitisticos. 

#vamos ver primeiro se o total_avc tem distribuição normal em todos os distritos

ggplot(avc_regiao_tempo, aes(x = Taxa_AVC)) +
  geom_histogram(bins = 15, fill = "skyblue", color = "black") +
  facet_wrap(~ `distrito_da_ocorrencia`, scales = "free") +
  theme_minimal()


# Aplicar o teste shapiro 
shapiro_results <- avc_regiao_tempo %>%
  group_by(distrito_da_ocorrencia) %>%
  summarise(p_value = shapiro.test(Taxa_AVC)$p.value)

# Print
print(shapiro_results)

# Homogeneidade das variâncias entre os grupos

levene_result <- leveneTest(Taxa_AVC ~ distrito_da_ocorrencia, data = avc_regiao_tempo)
Warning in leveneTest.default(y = y, group = group, ...) :
  group coerced to factor.
# Printar o resultado
print(levene_result)
Levene's Test for Homogeneity of Variance (center = median)
       Df F value    Pr(>F)    
group  17  9.8049 < 2.2e-16 ***
      450                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#conclusão: os dados são distribuidos normalmente e as variâncias são significativamente diferentes. Logo, vamos fazer o teste Welch ANOVA (oneway.test) para comparar as médias das taxas de AVC por 100.000 habitantes entre distritos, sem assumir variâncias iguais.

# Welch ANOVA
oneway.test(Taxa_AVC ~ `distrito_da_ocorrencia`, data = avc_regiao_tempo, var.equal = FALSE)

    One-way analysis of means (not assuming equal variances)

data:  Taxa_AVC and distrito_da_ocorrencia
F = 32.86, num df = 17.00, denom df = 167.03, p-value < 2.2e-16
#vamos ver como a taxa média de AVC evoluiu ao longo dos anos por distrito

avc_regiao_tempo <- avc_regiao_tempo %>%
  mutate(Ano = substr(Mes_Ano, 1, 4))  # extrai os 4 primeiros caracteres como ano

media_anual_distrito <- avc_regiao_tempo %>%
  group_by(Ano, `distrito_da_ocorrencia`) %>%
  summarise(Media_Taxa_AVC = mean(Taxa_AVC, na.rm = TRUE), .groups = "drop")

ggplot(media_anual_distrito, aes(x = Ano, y = Media_Taxa_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
  geom_line(size = 1) +
  geom_point(size = 1.5) +
  labs(title = "Evolução Anual da Taxa de AVC por Distrito",
       x = "Ano",
       y = "Taxa média de AVC por 100.000 habitantes",
       color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


#  Heatmap 
ggplot(media_anual_distrito, aes(x = Ano, y = reorder(`distrito_da_ocorrencia`, -Media_Taxa_AVC))) +
  geom_tile(aes(fill = Media_Taxa_AVC), color = "white") +
  scale_fill_gradient(low = "white", high = "red") +
  labs(title = "Heat Map: Stroke Rate by District and Year",
       x = "Year",
       y = "District",
       fill = "Rate") +
  theme_minimal()


## A mesma análise mas para hipertensos 
# 1. Dados mensais filtrados (2022-01 a 2024-02)
hipertensao_tempo <- hyp_final %>%
  mutate(Mes_Ano = format(ym(tempo), "%Y-%m")) %>%
  filter(Mes_Ano >= "2022-01", Mes_Ano <= "2024-02") %>%
  group_by(Mes_Ano, distritos.x) %>%
  summarise(
    Total_Hipertensao_Controlada = sum(as.numeric(total),na.rm = TRUE),
    .groups = "drop") %>%
  mutate( Populacao = populacao_distritos[distritos.x],
          Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / Populacao) * 100000
  )%>%
  st_drop_geometry(hipertensao_tempo)%>%
  rename(Distrito = distritos.x)

# 2. Total acumulado por distrito
hipertensao_total <- hipertensao_tempo %>%
  group_by(Distrito) %>%
  summarise(Total_Hipertensao_Controlada = sum(Total_Hipertensao_Controlada, na.rm = TRUE)) %>%
  arrange(desc(Total_Hipertensao_Controlada))


# Gráfico de total acumulado
ggplot(hipertensao_total, aes(x = reorder(Distrito, -Total_Hipertensao_Controlada), y = Total_Hipertensao_Controlada)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = round(Total_Hipertensao_Controlada)), vjust = -0.2, size = 2) +
  labs(title = "Total Patients with Controlled Hypertension by District",
       x = "District", y = "Patients") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))



# Distribuição ao longo do tempo por distrito

ggplot(hipertensao_tempo, aes(x = Mes_Ano, y = Total_Hipertensao_Controlada, color = `Distrito`, group = `Distrito`)) +
  geom_line() +
  labs(title = "Evolução Mensal de Registos de hipertensao por Distrito",
       x = "Mês", y = "Total de Hipertensão", color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))



# 3. Gráfico de evolução mensal das taxas
ggplot(hipertensao_tempo, aes(x = Mes_Ano, y = Taxa_Hipertensao_Controlada, color = Distrito, group = Distrito)) +
  geom_line() +
  labs(title = "Evolução mensal da Taxa de Hipertensão Controlada por Distrito",
       x = "Mês", y = "Taxa de Hipertensão por 100.000 habitantes", color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1
  ))



# 4. Média da taxa por distrito
ranking_distritos <- hipertensao_tempo %>%
  group_by(Distrito) %>%
  summarise(Media_Taxa_Hipertensao_Controlada = mean(Taxa_Hipertensao_Controlada, na.rm = TRUE)) %>%
  arrange(desc(Media_Taxa_Hipertensao_Controlada))

# Gráfico de ranking das taxas médias
ggplot(ranking_distritos, aes(x = reorder(Distrito, Media_Taxa_Hipertensao_Controlada), y = Media_Taxa_Hipertensao_Controlada)) +
  geom_col(fill = "darkgreen") +
  geom_text(aes(label = round(Media_Taxa_Hipertensao_Controlada, 1)), hjust = -0.1, size = 2) +
  coord_flip() +
  labs(title = "Controlled Hypertension Rate by District",
       x = "District", y = "Rate") +
  theme_minimal()



# 5. Histogramas por distrito (distribuição das taxas)
ggplot(hipertensao_tempo, aes(x = Taxa_Hipertensao_Controlada)) +
  geom_histogram(bins = 15, fill = "skyblue", color = "black") +
  facet_wrap(~ Distrito, scales = "free") +
  theme_minimal()


# 6. Teste de normalidade (Shapiro-Wilk)
shapiro_results <- hipertensao_tempo %>%
  group_by(Distrito) %>%
  summarise(p_value = shapiro.test(Taxa_Hipertensao_Controlada)$p.value)

print(shapiro_results)

# 7. Teste de homogeneidade das variâncias (Levene)
leveneTest(Taxa_Hipertensao_Controlada ~ Distrito, data = hipertensao_tempo)
Warning in leveneTest.default(y = y, group = group, ...) :
  group coerced to factor.
Levene's Test for Homogeneity of Variance (center = median)
       Df F value  Pr(>F)  
group  17  1.9335 0.01402 *
      449                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
 
kruskal.test(Taxa_Hipertensao_Controlada ~ Distrito, data = hipertensao_tempo)

    Kruskal-Wallis rank sum test

data:  Taxa_Hipertensao_Controlada by Distrito
Kruskal-Wallis chi-squared = 406.15, df = 17, p-value < 2.2e-16
# Partindo do objeto `hipertensao_tempo` já existente e filtrado (2022-2024)

# 1. Extrair o ano
hipertensao_tempo <- hipertensao_tempo %>%
  mutate(Ano = substr(Mes_Ano, 1, 4))

# 2. Calcular média anual da taxa por distrito
media_anual_distrito <- hipertensao_tempo %>%
  group_by(Ano, Distrito) %>%
  summarise(Media_Taxa_Hipertensao_Controlada = mean(Taxa_Hipertensao_Controlada, na.rm = TRUE), .groups = "drop")

# 3. Gráfico de linhas: Evolução anual
ggplot(media_anual_distrito, aes(x = Ano, y = Media_Taxa_Hipertensao_Controlada, color = Distrito, group = Distrito)) +
  geom_line(size = 1) +
  geom_point(size = 1.5) +
  labs(title = "Evolução Anual da Taxa de Hipertensão Controlada por Distrito",
       x = "Ano",
       y = "Taxa média por 100.000 habitantes",
       color = "Distrito") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# 4. Heatmap: Mapa de calor por distrito e ano
ggplot(media_anual_distrito, aes(x = Ano, y = reorder(Distrito, -Media_Taxa_Hipertensao_Controlada))) +
  geom_tile(aes(fill = Media_Taxa_Hipertensao_Controlada), color = "white") +
  scale_fill_gradient(low = "white", high = "darkgreen") +
  labs(title = "Heat Map: Controlled Hypertension Rate by District and Year",
       x = "Year",
       y = "District",
       fill = "Rate") +
  theme_minimal()


#Vamos ajustar uma regressão linear da taxa média anual vs ano para cada distrito e ver o coeficiente da inclinação: 
# Converter o ano para numérico
media_anual_distrito$Ano_Num <- as.numeric(media_anual_distrito$Ano)

# Regressão linear por distrito
tendencias <- media_anual_distrito %>%
  group_by(Distrito) %>%
  summarise(
    inclinacao = coef(lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num))[2],
    p_valor = summary(lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num))$coefficients[2, 4]
  ) %>%
  arrange(inclinacao)

print(tendencias)

# Aplica o teste de Mann-Kendall globalmente
mk.test(media_anual_distrito$Media_Taxa_Hipertensao_Controlada)

    Mann-Kendall trend test

data:  media_anual_distrito$Media_Taxa_Hipertensao_Controlada
z = 0.13429, n = 54, p-value = 0.8932
alternative hypothesis: true S is not equal to 0
sample estimates:
           S         varS          tau 
1.900000e+01 1.796700e+04 1.327743e-02 
modelo_global <- lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num, data = media_anual_distrito)
summary(modelo_global)

Call:
lm(formula = Media_Taxa_Hipertensao_Controlada ~ Ano_Num, data = media_anual_distrito)

Residuals:
    Min      1Q  Median      3Q     Max 
-2966.1  -935.5   -27.2  1123.1  4027.1 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept) -27207.58  431123.04  -0.063    0.950
Ano_Num         17.59     213.11   0.083    0.935

Residual standard error: 1279 on 52 degrees of freedom
Multiple R-squared:  0.000131,  Adjusted R-squared:  -0.0191 
F-statistic: 0.006813 on 1 and 52 DF,  p-value: 0.9345

## COMPARAÇÃO COM AS TAXAS NOS ANOS COMUNS

# AVC
avc_regiao <- avc %>%
  group_by(`distrito_da_ocorrencia`) %>%
  summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE)) %>%
  rename(Distrito = `distrito_da_ocorrencia`)

# Hipertensão
hipertensao_total <- hipertensao_tempo %>%
  group_by(Distrito) %>%
  summarise(Total_Hipertensao_Controlada = sum(Total_Hipertensao_Controlada, na.rm = TRUE)) 

# Juntar
df_relacao <- full_join(avc_regiao, hipertensao_total, by = "Distrito") %>%
  mutate(
    Populacao = populacao_distritos[Distrito],
    Taxa_AVC = (Total_AVC / Populacao) * 100000,
    Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / Populacao) * 100000
  ) %>%
  drop_na()
ggplot(df_relacao, aes(x = Taxa_Hipertensao_Controlada, y = Taxa_AVC)) +
  geom_point(color = "darkblue", size = 3) +
  geom_smooth(method = "lm", se = TRUE, color = "red") +
  geom_text(aes(label = Distrito), vjust = -0.8, size = 3) +
  labs(title = "Relationship between Controlled Hypertension Rate and Stroke Rate by District",
       x = "Controlled Hypertension Rate per 100,000 inhabitants",
       y = "Stroke Rate per 100,000 inhabitants") +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

# ver se tenho outliers 

boxplot(df_relacao$Taxa_Hipertensao_Controlada,
        main = "Boxplot of Controlled Hypertension Rate by District",
        ylab = "Rate")


# Boxplot for Stroke Rate
boxplot(df_relacao$Taxa_AVC,
        main = "Boxplot of Stroke Rate by District",
        ylab = "Rate")


# Para Taxa_Hipertensao_Controlada
x <- df_relacao$Taxa_Hipertensao_Controlada
Q1 <- quantile(x, 0.25, na.rm = TRUE)
Q3 <- quantile(x, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1

# Limites inferior e superior
lim_inf <- Q1 - 1.5 * IQR
lim_sup <- Q3 + 1.5 * IQR

# Ver quais são os outliers
outliers <- x[x < lim_inf | x > lim_sup]
print(outliers)
named numeric(0)
#Não tem outliers
#
# Correlação
cor.test(df_relacao$Taxa_Hipertensao_Controlada, df_relacao$Taxa_AVC, method = "pearson")

    Pearson's product-moment correlation

data:  df_relacao$Taxa_Hipertensao_Controlada and df_relacao$Taxa_AVC
t = -1.4182, df = 16, p-value = 0.1753
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.6929269  0.1572414
sample estimates:
       cor 
-0.3341598 
# Regressão
summary(lm(Taxa_AVC ~ Taxa_Hipertensao_Controlada, data = df_relacao))

Call:
lm(formula = Taxa_AVC ~ Taxa_Hipertensao_Controlada, data = df_relacao)

Residuals:
   Min     1Q Median     3Q    Max 
-68.30 -28.38 -18.96  27.39 106.73 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)   
(Intercept)                  3.016e+02  9.846e+01   3.063  0.00743 **
Taxa_Hipertensao_Controlada -6.371e-04  4.493e-04  -1.418  0.17533   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 49.4 on 16 degrees of freedom
Multiple R-squared:  0.1117,    Adjusted R-squared:  0.05614 
F-statistic: 2.011 on 1 and 16 DF,  p-value: 0.1753

# Juntar por Distrito e Mês


avc_regiao_tempo <- avc_regiao_tempo %>%
  rename(Distrito = distrito_da_ocorrencia)


dados_mensais_combinados <- inner_join(avc_regiao_tempo, hipertensao_tempo,
                                       by = c("Mes_Ano", "Distrito"),
                                       suffix = c("_AVC", "_Hipertensao")) %>%
  select(Mes_Ano, Distrito, Taxa_AVC, Taxa_Hipertensao_Controlada)

# Correlação de Pearson por distrito
correlacoes_distrito <- dados_mensais_combinados %>%
  group_by(Distrito) %>%
  summarise(
    correlacao = cor(Taxa_AVC, Taxa_Hipertensao_Controlada, use = "complete.obs", method = "pearson"),
    .groups = "drop"
  ) %>%
  arrange(correlacao)

print(correlacoes_distrito)

ggplot(correlacoes_distrito, aes(x = reorder(Distrito, correlacao), y = correlacao)) +
  geom_col(fill = "purple") +
  geom_text(aes(label = round(correlacao, 2)), hjust = -0.2, size = 3) +
  coord_flip() +
  labs(title = "Correlação entre Taxa de AVC e Hipertensão Controlada por Distrito",
       x = "Distrito", y = "Correlação (r)") +
  theme_minimal()


# Juntar os dados mensais
dados_mensais_combinados <- inner_join(avc_regiao_tempo, hipertensao_tempo,
                                       by = c("Mes_Ano", "Distrito"),
                                       suffix = c("_AVC", "_Hipertensao")) %>%
  select(Mes_Ano, Distrito, Taxa_AVC, Taxa_Hipertensao_Controlada)

# Calcular correlação e p-valor por distrito
correlacoes_distrito <- dados_mensais_combinados %>%
  group_by(Distrito) %>%
  summarise(
    r = cor(Taxa_AVC, Taxa_Hipertensao_Controlada, use = "complete.obs", method = "pearson"),
    p_value = cor.test(Taxa_AVC, Taxa_Hipertensao_Controlada)$p.value,
    .groups = "drop"
  ) %>%
  arrange(r)

# Ver distritos com correlação negativa significativa
correlacoes_significativas <- correlacoes_distrito %>%
  filter(r < -0.3, p_value < 0.05)

print(correlacoes_significativas)

ggplot(correlacoes_distrito, aes(x = reorder(Distrito, r), y = r, fill = p_value < 0.05 & r < -0.3)) +
  geom_col() +
  geom_text(aes(label = round(r, 2)), hjust = -0.2, size = 3) +
  coord_flip() +
  scale_fill_manual(values = c("grey70", "darkred"), labels = c("Não significativa", "Significativa"), name = "Correlação negativa significativa") +
  labs(title = "Correlação entre Hipertensão Controlada e AVC por Distrito",
       x = "Distrito", y = "Coeficiente de Correlação (r)") +
  theme_minimal()

NA
NA
# Correlação entre hipertenção e avc com as taxas
# Considerando o maior período de tempo dado pela data

#população média pr distritos entre 2015 e 2023
populacao_media <- c(
  Lisboa = 2276293,
  Porto = 1795549,
  Setubal = 869770,
  Braga = 843697,
  Aveiro = 703022,
  Faro = 462522,
  Leiria = 457242,
  Santarem = 437520,
  Coimbra = 411935,
  Viseu = 362275,
  Madeira = 251025,
  Acores = 238127,
  Viana_do_Castelo = 234672,
  Vila_Real = 195422,
  Castelo_Branco = 183996,
  Evora = 155441,
  Beja = 144772,
  Guarda = 148932,
  Braganca = 127356,
  Portalegre = 109975
)

hipertensao_tempo_all <- hyp_final %>%
  mutate(Mes_Ano = format(ym(tempo), "%Y-%m")) %>%
  group_by(Mes_Ano, distritos.x) %>%
  summarise(
    Total_Hipertensao_Controlada = sum(as.numeric(total), na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    Populacao = populacao_media[distritos.x],
    Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / populacao_media) * 100000
  )
Warning: There was 1 warning in `stopifnot()`.
ℹ In argument: `Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada/populacao_media) *
  1e+05`.
Caused by warning in `Total_Hipertensao_Controlada / populacao_media`:
! longer object length is not a multiple of shorter object length
hipertensao_total_2015 <- hipertensao_tempo_all %>%
  group_by(distritos.x) %>%
  summarise(Taxa_Hipertensao_Controlada = sum(Taxa_Hipertensao_Controlada, na.rm = TRUE)) %>%
  arrange(desc(Taxa_Hipertensao_Controlada))%>%
  rename(Distrito = distritos.x)


avc_hipertensao_all <- avc_regiao_tempo %>%
  inner_join(hipertensao_total_2015, by = "Distrito")

ggplot(avc_hipertensao_all, aes(x = Taxa_Hipertensao_Controlada, y = Taxa_AVC)) +
  geom_point(color = "steelblue", size = 3) +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Correlation between Controlled Hypertension Rate and Stroke Rate by District",
       x = "Controlled Hypertension Rate from 2015 to 2024",
       y = "Stroke Rate from 2022 to 2024") +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

correlacao <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC)
print(correlacao)
[1] -0.1876239
#Testes não paramétricos
#correlação de spearman - monótona não linear
c <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC, method = "spearman")
print(c)
[1] -0.1545749
# medida não paramétrica que avalia a associação monotônica entre duas variáveis. Ou seja, verifica se, à medida que uma variável aumenta, a outra tende a aumentar (ou diminuir), sem exigir uma relação linear.
#existe uma correlação neagtiva fraca (-0.2125704) entre as duas variáveis


#coreelação de kendall - mede a força e a direção da relação monotônica
k <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC, method = "kendall")
print(k)
[1] -0.1179419
resultado <- cor.test(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC,
                      method = "kendall")
print(resultado)

    Kendall's rank correlation tau

data:  avc_hipertensao_all$Taxa_Hipertensao_Controlada and avc_hipertensao_all$Taxa_AVC
z = -3.7095, p-value = 0.0002077
alternative hypothesis: true tau is not equal to 0
sample estimates:
       tau 
-0.1179419 
#existe uma correlação negativa fraca (-0.1589298) entre as duas variáveis
# 1.72e-06 < 0,05: A correlação é estatisticamente significativa, embora fraca.
#correlação AVC e hipertensão SÓ nos anos em comum


avc_hipertensao <- avc_regiao  %>%
  inner_join(hipertensao_total, by = "Distrito")

ggplot(avc_hipertensao, aes(x = Total_Hipertensao_Controlada, y = Total_AVC)) +
  geom_point(color = "steelblue", size = 3) +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Correlação entre Hipertensão Controlada e Registos de AVC por Distrito",
       x = "Total de Hipertensos Controlados",
       y = "Total de Registos de AVC") +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

correlacao <- cor(avc_hipertensao$Total_Hipertensao_Controlada, avc_hipertensao$Total_AVC)
print(correlacao)
[1] 0.9733902

```

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CgojIExpc3RhIGRlIHBhY290ZXMgbmVjZXNzw6FyaW9zCnBhY2thZ2VzIDwtIGMoCiAgImRwbHlyIiwgImdncGxvdDIiLCAiY29ycnBsb3QiLCAiY2FyIiwgImx1YnJpZGF0ZSIsCiAgInRpZHlyIiwgInN0cmluZ3IiLCAic3RyaW5naSIsICJyc3RhdGl4IiwgInNmIiwKICAicHVycnIiLCAiR0dhbGx5IiwgIkZhY3RvTWluZVIiLCAiZmFjdG9leHRyYSIsCiAgInBhdGNod29yayIsICJtaWNlIiwgImphbml0b3IiLCAic2NhbGVzIiwgInRyZW5kIgopCgojIEluc3RhbGFyIGFwZW5hcyBvcyBxdWUgbsOjbyBlc3TDo28gaW5zdGFsYWRvcwppbnN0YWxsZWQgPC0gcGFja2FnZXMgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkKaWYgKGFueSghaW5zdGFsbGVkKSkgewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXNbIWluc3RhbGxlZF0pCn0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShjYXIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyc3RhdGl4KQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShGYWN0b01pbmVSKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KG1pY2UpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkodHJlbmQpCgojbGVyIGRhdGEKaHlwZXJ0ZW5zaW9uIDwtIHJlYWQuY3N2MigiaHR0cHM6Ly90cmFuc3BhcmVuY2lhLnNucy5nb3YucHQvYXBpL2V4cGxvcmUvdjIuMS9jYXRhbG9nL2RhdGFzZXRzL2hpcGVydGVuc2FvL2V4cG9ydHMvY3N2P2xhbmc9cHQmdGltZXpvbmU9RXVyb3BlJTJGTGlzYm9uIikKYXZjIDwtIHJlYWQuY3N2MigiaHR0cHM6Ly90cmFuc3BhcmVuY2lhLnNucy5nb3YucHQvYXBpL2V4cGxvcmUvdjIuMS9jYXRhbG9nL2RhdGFzZXRzL2V2b2x1Y2FvLXNpdHVhY29lcy1kb2VudGVzLXNpbmFpcy1zaW50b21hcy1kZS1hdmMvZXhwb3J0cy9jc3Y/bGFuZz1wdCZ0aW1lem9uZT1FdXJvcGUlMkZMb25kb24mdXNlX2xhYmVscz10cnVlJmRlbGltaXRlcj0lM0IiKQoKIyMgVmFtb3MgcHJpbWVpcm8gYW5hbGlzYXIgbyBkYXRhc2V0IGh5cGVydGVuc2lvbjoKCiNWZXIgbWlzc2luZyB2YWx1ZXMgCgpvdXQgPC0gc2FwcGx5KGh5cGVydGVuc2lvbiwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpIHwgeCA9PSAiIikpCiAgICAgICAKI25vIGRhdGFmcmFtZSBkZSBoaXBlcnRlbnPDo28gZXhpc3RlbSAyNCBtaXNzaW5nIHZhbHVlcyBuYSB2YXJpYXZlbCBwb250b19vdV9sb2NhbGl6YWNhb19nZW9ncmFmaWNhLgojUmV0aXJvIGFzIG9ic2VydmHDp8O1ZXMgb3UgZmHDp28gaW1wdXRhw6fDo28/IFRlbmhvIGRlIHZlciBzZSDDqSByZWxldmFudGUgdGFtYsOpbQoKCiNhdmFsaWFyIHJlbGV2w6JuY2lhIGRhIHZhcmnDoXZlbAojdmVyIHJlbGV2w6JuY2lhIGRhIGxvY2FsaXphw6fDo28gcGFyYSBvcyB2YWxvcmVzIGRlIGhpcGVydGVuw6fDo28KIyBNb2RlbG8gY29tcGxldG8gLSByZWdyZXNzw6NvIGRlIHBvaXNzb24gKHZhcmnDoXZlbCDDqSB1bWEgY29udGFnZW0pCm1vZGVsb19jb21wbGV0byA8LSBnbG0oY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiB+IAogICAgcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSArIHJlZ2lhbyArIHRlbXBvLCBkYXRhID0gaHlwZXJ0ZW5zaW9uKQoKIyBNb2RlbG8gc2VtIHBvbnRvX291X2xvY2FsaXphY2FvX2dlb2dyYWZpY2EKbW9kZWxvX3JlZHV6aWRvIDwtIGdsbShjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uIH4gCiAgICByZWdpYW8gKyB0ZW1wbywgZGF0YSA9IGh5cGVydGVuc2lvbikKCiMgVGVzdGUgZGUgcmF6w6NvIGRlIHZlcm9zc2ltaWxoYW7Dp2EKYW5vdmEobW9kZWxvX3JlZHV6aWRvLCBtb2RlbG9fY29tcGxldG8sIHRlc3QgPSAiQ2hpc3EiKQojdmFyacOhdmVsIHJlbGV2YW50ZQoKCnRvdGFsX2RhdGEgPC0gIGxlbmd0aChoeXBlcnRlbnNpb24kcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkKcGVyY2VudGFnZV9udWxsIDwtIDEwMCphcy5udW1lcmljKG91dFsicG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSJdKS90b3RhbF9kYXRhCgojcGVyY2VudGFnZW0gZGUgbWlzc2luZyB2YWx1ZXMgw6kgMC4zNjU5IC0gbXVpdG8gcGVxdWVuYSBsb2dvIGVtIHByaW5jw61waW8gcG9kZSBzZXIgYWNlaXTDoXZlbCByZW1vdmUtbGFzCgoKI3ZlciBkaXN0cmlidWnDp8OjbyB0ZW1wb3JhbCBkb3MgdmFsb3JlcyBzZW0gbG9jYWxpemHDp8OjbyBjb3JyZXNwb25kZW50ZSBlIHJlc3BldGl2YSBwZXJjZW50YWdlbQp3aGVyZV9uYSA8LSBoeXBlcnRlbnNpb24gJT4lCiAgZmlsdGVyKHBvbnRvX291X2xvY2FsaXphY2FvX2dlb2dyYWZpY2EgPT0gIiIgfCBpcy5uYSAocG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkpICU+JQogIGNvdW50KHRlbXBvLCBuYW1lID0gImF1c2VudGVzIikKCnRvdGFsX3BlcmlvZCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgY291bnQodGVtcG8sIG5hbWUgPSAidG90YWwiKQoKcGVyY2VudGFnZXMgPC0gbGVmdF9qb2luKHdoZXJlX25hLCB0b3RhbF9wZXJpb2QsIGJ5ID0gInRlbXBvIikgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2VtID0gcm91bmQoKGF1c2VudGVzIC8gdG90YWwpICogMTAwLCAyKSkKCiNhIHBlcmNlbnRhZ2VtIHNvYmUgNS4xMyUgLCBjcmlhbmRvIGR1dmlkYXMgc29icmUgYSByZW1vw6fDo28KCiNjb21wb3J0YW1lbnRvIGRvcyB2YWxvcmVzIHNlbSBsb2NhbGl6YcOnw6NvIGNvcnJlc3BvbmRlbnRlCiMgQWRpY2lvbmEgdW1hIGZsYWcgcGFyYSBtaXNzaW5nIG91IG7Do28KaHlwZXJ0ZW5zaW9uJGxvY2FsaXphY2FvIDwtIGlmZWxzZShoeXBlcnRlbnNpb24kcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSA9PSAiIiB8IGlzLm5hKGh5cGVydGVuc2lvbiRwb250b19vdV9sb2NhbGl6YWNhb19nZW9ncmFmaWNhKSwgRkFMU0UsIFRSVUUpCgojIENvbXBhcmEgYXMgbcOpZGlhcyBlIG1lZGlhbmFzCiMgdG90YWwgZGUgZGFkb3MKbWV0cmljYV90b3RhbCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgICAgc3VtbWFyaXNlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgbGlzdChtZWRpYSA9IG1lYW4sIG1lZGlhbmEgPSBtZWRpYW4sIHZhcmlhbmNpYSA9IHZhciksIG5hLnJtID0gVFJVRSkpCiAKIyBkYWRvcyBjb20gbG9jYWxpemHDp8OjbwptZXRyaWNhX2NvbV9sb2NhbCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgICAgZmlsdGVyKGxvY2FsaXphY2FvICE9IEZBTFNFKSAlPiUKICAgICBzdW1tYXJpc2UoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCBsaXN0KG1lZGlhID0gbWVhbiwgbWVkaWFuYSA9IG1lZGlhbiwgdmFyaWFuY2lhID0gdmFyKSwgbmEucm0gPSBUUlVFKSkKCiNvcyB2YWxvcmVzIGRhcyBtw6l0cmljYXMgY29tcGFyYWRhcyBuw6NvIHPDo28gbXVpdG8gZGlzY3JlcGFudGVzIGxvZ28gY29uY2x1aW1vcyBxdWUgYSBtZWxob3IgYWJvcmRhZ2VtIMOpIGEgaW1wdXRhw6fDo28gcG9ycXVlIG9zIGRhZG9zIHNlbSBsb2NhbGl6YcOnw6NvIHJlcHJlc2VudGFtIGEgYW1vc3RyYSwgYSBxdWUgw6kgY29uZmlybWFkbyBwZWxvIFdlbGNoIFR3byBTYW1wbGUgdC10ZXN0CmFtb3N0cmExIDwtIGh5cGVydGVuc2lvbiRjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uCmFtb3N0cmEyIDwtIGh5cGVydGVuc2lvbiAlPiUKICBmaWx0ZXIobG9jYWxpemFjYW8gIT0gRkFMU0UpICU+JQogIHB1bGwoY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbikKCnQudGVzdChhbW9zdHJhMSwgYW1vc3RyYTIsIHZhci5lcXVhbCA9IEZBTFNFKQoKIyBwLXZhbHVlPSAwLjY0NjMgPiAwLjA1ICwgbsOjbyByZWplaXRhbW9zIGEgaGlwb3Rlc2UgbnVsYS4gQ29uY2x1w61tb3MgcXVlIG7Do28gaMOhIGRpZmVyZW7Dp2Egc2lnbmlmaWNhdGl2YSBlbnRyZSBhcyBtw6lkaWFzLgpgYGAKCmBgYHtyfQojIHRvcm5hciBpbmRleCBkYSBsb2NhbGl6YcOnw6NvIG1haXMgYWNlc3NpdmVsIHBhcmEgcXVlIGEgaW1wdXRhw6fDo28gcG9zc2EgZmF6ZXIgbWFpcyBzZW50aWRvCiMgUmVub21lYXIgYSBjb2x1bmEgZGUgY29vcmRlbmFkYXMKaHlwZXJ0ZW5zaW9uIDwtIGh5cGVydGVuc2lvbiAlPiUKICByZW5hbWUoY29vcmRzID0gcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkKCiMgU2VwYXJhciBjb29yZGVuYWRhcyBlbSBsYXQvbG9uCiMgU2VwYXJhciBhIGNvbHVuYSBkZSBjb29yZGVuYWRhcyBlbSBsYXRpdHVkZSBlIGxvbmdpdHVkZQoKaHlwX2Nvb3JkcyA8LSBoeXBlcnRlbnNpb24gJT4lCiAgc2VwYXJhdGUoY29vcmRzLCBpbnRvID0gYygibGF0IiwgImxvbiIpLCBzZXAgPSAiLCIsIGNvbnZlcnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoCiAgICBsYXQgPSBhcy5udW1lcmljKHN0cl9yZXBsYWNlKGxhdCwgIiwiLCAiLiIpKSwKICAgIGxvbiA9IGFzLm51bWVyaWMoc3RyX3JlcGxhY2UobG9uLCAiLCIsICIuIikpLAogICAgcHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCA9IGFzLm51bWVyaWMocHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCkKICApCgojIEdhcmFudGlyIHF1ZSBhIHByb3BvcsOnw6NvIGVzdGVqYSBlbSBmb3JtYXRvIG51bcOpcmljbwpoeXBfY29vcmRzIDwtIGh5cF9jb29yZHMgJT4lCiAgbXV0YXRlKHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTAgPSBhcy5udW1lcmljKHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQoKCiMgQ29udmVydGVyIHBhcmEgc2YKaHlwX3NmIDwtIGh5cF9jb29yZHMgJT4lCiAgbXV0YXRlKGdlb21ldHJ5ID0gcG1hcChsaXN0KGxvbiwgbGF0KSwgZnVuY3Rpb24oeCwgeSkgewogICAgaWYgKGlzLm5hKHgpIHx8IGlzLm5hKHkpKSB7CiAgICAgIHN0X2dlb21ldHJ5Y29sbGVjdGlvbigpCiAgICB9IGVsc2UgewogICAgICBzdF9wb2ludChjKHgsIHkpKQogICAgfQogIH0pKSAlPiUKICBzdF9hc19zZihjcnMgPSA0MzI2KQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyA0LiBDYXJyZWdhciBzaGFwZWZpbGVzIChuw612ZWlzIDIpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBNdW5pY8OtcGlvcyAoTsOtdmVsIDIpCm11bmljaXBpb3MgPC0gc3RfcmVhZCgiZ2FkbTQxX1BSVF8yLnNocCIpICU+JSBzdF90cmFuc2Zvcm0oNDMyNikKbXVuaWNpcGlvcyA8LSBtdW5pY2lwaW9zICU+JQogIHJlbmFtZShkaXN0cml0b3MgPSBOQU1FXzEsCiAgICAgICAgIG11bmljaXBpbyA9IE5BTUVfMikKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIDUuIEpvaW4gZXNwYWNpYWw6IEhpcGVydGVuc8OjbyDihpIgTXVuaWPDrXBpbwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmh5cGVyX2pvaW5lZCA8LSBzdF9qb2luKGh5cF9zZiwgbXVuaWNpcGlvcywgam9pbiA9IHN0X3dpdGhpbikKCmBgYAoKYGBge3J9CiNpbXB1dGFjYW8gY29tIGJhc2UgbmEgc2VtZWxoYW7Dp2EgZGUgdmFsb3JlcwoKIyBDYWxjdWxhciBhIG3DqWRpYSBwb3IgZ3J1cG8gbXVuaWNpcGlvCm1lYW5fcGVyX2dyb3VwIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKG1lYW5fY29udGFnZW0gPSBtZWFuKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gVFJVRSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKZGVzdmlvIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKGRlc3Zpb19jb250YWdlbSA9IHNkKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gRkFMU0UpKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCgppbnRlcnZhbG8gPC0gbWVhbl9wZXJfZ3JvdXAgJT4lCiAgbGVmdF9qb2luKGRlc3ZpbywgYnkgPSAibXVuaWNpcGlvIikgJT4lCiAgbXV0YXRlKAogICAgbGltaXRlX2luZmVyaW9yID0gbWVhbl9jb250YWdlbSAtIGRlc3Zpb19jb250YWdlbSwKICAgIGxpbWl0ZV9zdXBlcmlvciA9IG1lYW5fY29udGFnZW0gKyBkZXN2aW9fY29udGFnZW0KICApCgojIEltcHV0YXIgbXVuaWNpcGlvIGNvbSBiYXNlIG5hIG3DqWRpYSBtYWlzIHByw7N4aW1hIGRhIGNvbnRhZ2VtCmh5cF9maW5hbCA8LSBoeXBlcl9qb2luZWQgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShtdW5pY2lwaW8gPSBpZl9lbHNlKAogICAgaXMubmEobXVuaWNpcGlvKSwKICAgIHsKICAgICAgY29udF92YWwgPC0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbgogICAgICAKICAgICAgIyBWZXJpZmljYSBxdWFpcyBtdW5pY8OtcGlvcyB0w6ptIG8gdmFsb3IgZGVudHJvIGRvIGludGVydmFsbwogICAgICBkZW50cm9faW50ZXJ2YWxvIDwtIGludGVydmFsbyAlPiUKICAgICAgICBmaWx0ZXIoY29udF92YWwgPj0gbGltaXRlX2luZmVyaW9yICYgY29udF92YWwgPD0gbGltaXRlX3N1cGVyaW9yKQoKICAgICAgaWYgKG5yb3coZGVudHJvX2ludGVydmFsbykgPiAwKSB7CiAgICAgICAgIyBFbnRyZSBvcyB2w6FsaWRvcywgcGVnYSBvIGRlIG3DqWRpYSBtYWlzIHByw7N4aW1hCiAgICAgICAgZGlmZnMgPC0gYWJzKGRlbnRyb19pbnRlcnZhbG8kbWVhbl9jb250YWdlbSAtIGNvbnRfdmFsKQogICAgICAgIGRlbnRyb19pbnRlcnZhbG8kbXVuaWNpcGlvW3doaWNoLm1pbihkaWZmcyldCiAgICAgIH0gZWxzZSB7CiAgICAgICAgTkFfY2hhcmFjdGVyXwogICAgICB9CiAgICB9LAogICAgbXVuaWNpcGlvCiAgKSkgJT4lCiAgdW5ncm91cCgpJT4lCiAgZmlsdGVyKCFpcy5uYShtdW5pY2lwaW8pKQoKCgp0YWJlbGFfY29ycmVzcG9uZGVuY2lhIDwtIG11bmljaXBpb3MgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIHNlbGVjdChkaXN0cml0b3MsIG11bmljaXBpbykgJT4lCiAgZGlzdGluY3QoKQoKaHlwX2ZpbmFsIDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUobXVuaWNpcGlvX2NsZWFuID0gc3RyaV90cmFuc19nZW5lcmFsKHRvbG93ZXIodHJpbXdzKG11bmljaXBpbykpLCAiTGF0aW4tQVNDSUkiKSkKCnRhYmVsYV9jb3JyZXNwb25kZW5jaWEgPC0gdGFiZWxhX2NvcnJlc3BvbmRlbmNpYSAlPiUKICBtdXRhdGUobXVuaWNpcGlvX2NsZWFuID0gc3RyaV90cmFuc19nZW5lcmFsKHRvbG93ZXIodHJpbXdzKG11bmljaXBpbykpLCAiTGF0aW4tQVNDSUkiKSkKCiMgMi4gRmF6IG8gam9pbiBjb20gYmFzZSBuYSB2ZXJzw6NvIGxpbXBhCmh5cF9maW5hbCA8LSBoeXBfZmluYWwgJT4lCiAgbGVmdF9qb2luKHRhYmVsYV9jb3JyZXNwb25kZW5jaWEgJT4lIHNlbGVjdChtdW5pY2lwaW9fY2xlYW4sIGRpc3RyaXRvcyksIGJ5ID0gIm11bmljaXBpb19jbGVhbiIpCmBgYAoKYGBge3J9CgojIC0tLSBFZmVpdG8gZGEgaW1wdXRhw6fDo28gbmEgbcOpZGlhIC0tLQojIDEuIE3DqWRpYSBvcmlnaW5hbCBwb3IgZ3J1cG8KbWVhbl9hdHRyIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKG1lYW5fb3JpZ2luYWwgPSBtZWFuKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gVFJVRSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKIyAyLiBNw6lkaWEgYXDDs3MgaW1wdXRhw6fDo28gKGVtIGh5cF9maW5hbCkKbWVhbl9wZXJfZ3JvdXBfY29tX2ltcCA8LSBoeXBfZmluYWwgJT4lCiAgZ3JvdXBfYnkobXVuaWNpcGlvKSAlPiUKICBzdW1tYXJpc2UobWVhbl9pbXB1dGFkYSA9IG1lYW4oY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiwgbmEucm0gPSBUUlVFKSkgJT4lCiAgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpCgojIDMuIEp1bnRhciBtw6lkaWFzIG9yaWdpbmFsIGUgaW1wdXRhZGEKbWVhbnMgPC0gbGVmdF9qb2luKG1lYW5fYXR0ciwgbWVhbl9wZXJfZ3JvdXBfY29tX2ltcCwgYnkgPSAibXVuaWNpcGlvIikKCiMgNC4gR3LDoWZpY28gZGFzIG3DqWRpYXMKbWVhbnNfbG9uZyA8LSBtZWFucyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWVhbl9vcmlnaW5hbCwgbWVhbl9pbXB1dGFkYSksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInRpcG9fbWVkaWEiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibWVkaWEiKQoKZ3JhZmljbyA8LSBnZ3Bsb3QobWVhbnNfbG9uZywgYWVzKHggPSBtdW5pY2lwaW8sIHkgPSBtZWRpYSwgZmlsbCA9IHRpcG9fbWVkaWEpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJhw6fDo28gZGFzIG3DqWRpYXMgcG9yIG11bmljaXBpbyIsCiAgICAgICB4ID0gIk11bmljaXBpbyIsIHkgPSAiTcOpZGlhIGRhIGNvbnRhZ2VtIiwKICAgICAgIGZpbGwgPSAiVGlwbyBkZSBNw6lkaWEiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKZ2dzYXZlKGZpbGVuYW1lID0gImdyYWZpY29fbWVkaWFzX3Bvcl9ncnVwby5wbmciLCBwbG90ID0gZ3JhZmljbywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQoKCiMgNS4gRGlzdMOibmNpYSBlbnRyZSB2YWxvciBpbXB1dGFkbyBlIG3DqWRpYSBvcmlnaW5hbCBkbyBncnVwbwpkaXN0YW5jZSA8LSBoeXBfZmluYWwgJT4lCiAgZmlsdGVyKGxvY2FsaXphY2FvID09IEZBTFNFKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lCiAgbGVmdF9qb2luKG1lYW5fYXR0ciwgYnkgPSAibXVuaWNpcGlvIikgJT4lCiAgbXV0YXRlKGRpc3QgPSBtZWFuX29yaWdpbmFsIC0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbikKCiMgNi4gR3LDoWZpY28gZGUgbGluaGFzIHBhcmEgYW5hbGlzYXIgNS4KIyBDcmlhciBsaW1pdGVzIHBhcmEgYSByZWdpw6NvIHNvbWJyZWFkYSAoYmFuZGEgZGUgY29uZmlhbsOnYSkKZGlzdGFuY2UgPC0gZGlzdGFuY2UgJT4lCiAgbXV0YXRlKAogICAgeW1pbiA9IG1lYW5fb3JpZ2luYWwgLSBhYnMoZGlzdCksCiAgICB5bWF4ID0gbWVhbl9vcmlnaW5hbCArIGFicyhkaXN0KQogICkKCmdyYWZpY29fMiA8LSBnZ3Bsb3QoZGlzdGFuY2UsIGFlcyh4ID0gcmVvcmRlcihtdW5pY2lwaW8sIG1lYW5fb3JpZ2luYWwpLCB5ID0gbWVhbl9vcmlnaW5hbCwgZ3JvdXAgPSAxKSkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluID0geW1pbiwgeW1heCA9IHltYXgpLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGFscGhhID0gMC40KSArICAjIHJlZ2nDo28gc29tYnJlYWRhCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKyAgIyBsaW5oYSBkYSBtw6lkaWEKICBnZW9tX3BvaW50KGFlcyh5ID0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiksCiAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMikgKyAgIyBwb250b3MgZG8gdmFsb3IgaW1wdXRhZG8KICBsYWJzKAogICAgeCA9ICJNdW5pY8OtcGlvcyBjb20gdmFsb3JlcyBpbXB1dGFkb3MiLAogICAgeSA9ICJWYWxvciIsCiAgICB0aXRsZSA9ICJNw6lkaWEgb3JpZ2luYWwgdnMgZGlzdMOibmNpYSBkbyB2YWxvciBpbXB1dGFkbyIsCiAgICBzdWJ0aXRsZSA9ICJMaW5oYSBhenVsOiBtw6lkaWEgb3JpZ2luYWw7IFJlZ2nDo28gYXp1bCBjbGFyYTogZGlzdMOibmNpYTsgUG9udG9zIHZlcm1lbGhvczogdmFsb3JlcyBpbXB1dGFkb3MiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkKICApCgpnZ3NhdmUoZmlsZW5hbWUgPSAiZ3JhZmljb19kaXN0YW5jaWFzX3Bvcl9ncnVwby5wbmciLCBwbG90ID0gZ3JhZmljb18yLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApCgojIC0tLSBDb21wYXJhw6fDo28gZGEgZGlzdHJpYnVpw6fDo28gcmVnaW9uYWw6IGltcHV0YWRvcyB2cyByZWFpcyAtLS0KdGFiZWxhX2NvbXBhcmF0aXZhIDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUodGlwbyA9IGlmZWxzZShsb2NhbGl6YWNhbywgIlJlYWwiLCAiSW1wdXRhZG8iKSkgJT4lCiAgZ3JvdXBfYnkobXVuaWNpcGlvLCB0aXBvKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdyb3VwX2J5KHRpcG8pICU+JQogIG11dGF0ZShwcm9wID0gdG90YWwgLyBzdW0odG90YWwpKQoKcCA8LSBnZ3Bsb3QodGFiZWxhX2NvbXBhcmF0aXZhLCBhZXMoeCA9IHByb3AsIHkgPSBtdW5pY2lwaW8sIGZpbGwgPSB0aXBvKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWnDp8OjbyBkZSBNdW5pY8OtcGlvczogUmVhbCB2cyBJbXB1dGFkbyIsCiAgICAgICB5ID0gIk11bmljw61waW8iLCB4ID0gIlByb3BvcsOnw6NvIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKZ2dzYXZlKCJncmFmaWNvX2Rpc3RyaWJ1aWNhby5wbmciLCBwbG90ID0gcCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpID0gMzAwKQoKIyAtLS0gQ29ycmVsYcOnw6NvIC0tLQpjb3JfYmVmb3JlIDwtIGNvcigKICBoeXBlcl9qb2luZWQkY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiwKICBoeXBlcl9qb2luZWQkcHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCwKICB1c2UgPSAiY29tcGxldGUub2JzIgopCgpjb3JfYWZ0ZXIgPC0gY29yKAogIGh5cF9maW5hbCRjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uLAogIGh5cF9maW5hbCRwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwCikKCmNhdCgiQ29ycmVsYcOnw6NvIGFudGVzIGRhIGltcHV0YcOnw6NvOiIsIGNvcl9iZWZvcmUsICJcbiIpCmNhdCgiQ29ycmVsYcOnw6NvIGRlcG9pcyBkYSBpbXB1dGHDp8OjbzoiLCBjb3JfYWZ0ZXIsICJcbiIpCgojc3VtbWFyeQpzdW1tYXJ5KGh5cGVyX2pvaW5lZCAlPiUgc2VsZWN0KGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQpzdW1tYXJ5KGh5cF9maW5hbCAlPiUgc2VsZWN0KGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQoKCiMgLS0tIERpc3BlcnPDo28gZGFzIHZhcmnDoXZlaXMgcHJpbmNpcGFpcyAtLS0KZ2dwbG90KGh5cF9maW5hbCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uLAogICAgICAgICAgICAgICAgICAgICAgeSA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTAsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxvY2FsaXphY2FvKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhw6fDo286IFJlYWlzIHZzIEltcHV0YWRvcyIsIGNvbG9yID0gIkRhZG9zIHJlYWlzPyIpCgojIC0tLSBQQ0EgcGFyYSB2aXN1YWxpemHDp8OjbyBtdWx0aXZhcmlhZGEgLS0tCmRhZG9zX3BjYSA8LSBzdF9kcm9wX2dlb21ldHJ5KGh5cF9maW5hbFssIGMoImNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24iLCJwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwIildKQoKcmVzLnBjYSA8LSBQQ0EoZGFkb3NfcGNhLCBncmFwaCA9IEZBTFNFKQpmdml6X3BjYV9pbmQocmVzLnBjYSwgCiAgICAgICAgICAgICBoYWJpbGxhZ2UgPSBhcy5mYWN0b3IoaHlwX2ZpbmFsJGxvY2FsaXphY2FvKSwKICAgICAgICAgICAgIHRpdGxlID0gIlBDQTogSW1wdXRlZCB2cyBSZWFsIERhdGEiLAogICAgICAgICAgICAgcGFsZXR0ZSA9IGMoInJlZCIsICJibHVlIikpICAjIFZlcm1lbGhvID0gaW1wdXRhZG8sIEF6dWwgPSByZWFsCgoKZ2dwbG90KGh5cGVyX2pvaW5lZCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjUpICsgZ2d0aXRsZSgiQ29udGFnZW0gQW50ZXMgZGEgSW1wdXRhw6fDo28iKQoKZ2dwbG90KGh5cF9maW5hbCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJncmVlbiIsIGFscGhhID0gMC41KSArIGdndGl0bGUoIkNvbnRhZ2VtIERlcG9pcyBkYSBJbXB1dGHDp8OjbyIpCgpnZ3Bsb3QoaHlwZXJfam9pbmVkLCBhZXMoeCA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuNSkgKyBnZ3RpdGxlKCJQcm9wb3LDp8OjbyBBbnRlcyBkYSBJbXB1dGHDp8OjbyIpCgpnZ3Bsb3QoaHlwX2ZpbmFsLCBhZXMoeCA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImdyZWVuIiwgYWxwaGEgPSAwLjUpICsgZ2d0aXRsZSgiUHJvcG9yw6fDo28gRGVwb2lzIGRhIEltcHV0YcOnw6NvIikKCgoKI2ltcHV0YcOnw6NvIGNvbSBzdWNlc3NvCmBgYAoKYGBge3J9CgojQW5hbGlzZSB0ZW1wb3JhbCBkbyBkYXRhZnJhbWUgZGEgaGlwZXJ0ZW5zYW8gY29tIGltcHV0YWNhbwoKIyBDYWxjdWxhciBwcm9wb3LDp8OjbyB0b3RhbApoeXBfZmluYWwgPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZSh0b3RhbCA9IDEwMCAqIGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24gLyBwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwKQoKIyBUb3RhbCBwb3IgYW5vICh0b2RvcyBvcyB1dGVudGVzKQpoaXBlcnRlbnNhb19hbm8gPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZShBbm8gPSB5ZWFyKHltKHRlbXBvKSkpICU+JQogIGdyb3VwX2J5KEFubykgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKGFzLm51bWVyaWModG90YWwpLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCmdncGxvdChoaXBlcnRlbnNhb19hbm8sIGFlcyh4ID0gZmFjdG9yKEFubyksIHkgPSB0b3RhbCkpICsKICBnZW9tX2NvbChmaWxsID0gInN0ZWVsYmx1ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQodG90YWwpKSwgdmp1c3QgPSAtMC4yNSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIGRlIFV0ZW50ZXMgY29tIEhpcGVydGVuc8OjbyBwb3IgQW5vIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgVG90YWwgcG9yIGFubyBwYXJhIHBlc3NvYXMgY29tIG1lbm9zIGRlIDY1IGFub3MKaGlwZXJ0ZW5zYW9fYW5vX21lbm9zXzY1IDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUoQW5vID0geWVhcih5bSh0ZW1wbykpKSAlPiUKICBncm91cF9ieShBbm8pICU+JQogIHN1bW1hcmlzZShoaXBfbWVub3NfNjUgPSBzdW0oYXMubnVtZXJpYyhjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpCgpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fYW5vX21lbm9zXzY1LCBhZXMoeCA9IGZhY3RvcihBbm8pLCB5ID0gaGlwX21lbm9zXzY1KSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChoaXBfbWVub3NfNjUpKSwgdmp1c3QgPSAtMC4yNSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIGRlIFV0ZW50ZXMgY29tIG1lbm9zIGRlIDY1IGFub3MgY29tIEhpcGVydGVuc8OjbyBwb3IgQW5vIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgQ29tcGFyYcOnw6NvIGVudHJlIG1lbm9zIGRlIDY1IGUgNjUgb3UgbWFpcwpoaXBlcnRlbnNhb19jb21wX2FubyA8LSBoaXBlcnRlbnNhb19hbm8gJT4lCiAgbGVmdF9qb2luKGhpcGVydGVuc2FvX2Fub19tZW5vc182NSwgYnkgPSAiQW5vIikgJT4lCiAgbXV0YXRlKAogICAgaGlwX21lbm9zXzY1ID0gaWZlbHNlKGlzLm5hKGhpcF9tZW5vc182NSksIDAsIGhpcF9tZW5vc182NSksCiAgICBoaXBfbWFpc182NSA9IHRvdGFsIC0gaGlwX21lbm9zXzY1CiAgKSAlPiUKICBzZWxlY3QoQW5vLCBoaXBfbWVub3NfNjUsIGhpcF9tYWlzXzY1KSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhoaXBfbWVub3NfNjUsIGhpcF9tYWlzXzY1KSwKICAgIG5hbWVzX3RvID0gIkdyb3VwIiwKICAgIHZhbHVlc190byA9ICJ0b3RhbCIKICApICU+JQogIG11dGF0ZSgKICAgIEdyb3VwID0gZHBseXI6OnJlY29kZShHcm91cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAiaGlwX21lbm9zXzY1IiA9ICJVbmRlciA2NSB5ZWFycyBvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJoaXBfbWFpc182NSIgPSAiNjUgeWVhcnMgb3Igb2xkZXIiKQogICkKCiMgR3LDoWZpY28gZW1waWxoYWRvCmdncGxvdChoaXBlcnRlbnNhb19jb21wX2FubywgYWVzKHggPSBmYWN0b3IoQW5vKSwgeSA9IHRvdGFsLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicygKICAgIHRpdGxlID0gIiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBieSBBZ2UgYW5kIFllYXIiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIFBhdGllbnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKCgojIEhpcGVydGVuc8OjbyBwb3IgbcOqcyAtIFRvdGFsCmhpcGVydGVuc2FvX21lcyA8LSBoeXBfZmluYWwgJT4lCiAgbXV0YXRlKERhdGEgPSB5bSh0ZW1wbyksCiAgICAgICAgIE1lcyA9IG1vbnRoKERhdGEsIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lICAKICBncm91cF9ieShNZXMpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShhcy5udW1lcmljKHRvdGFsKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgYXJyYW5nZShtYXRjaChNZXMsIG1vbnRoLm5hbWUpKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCmdncGxvdChoaXBlcnRlbnNhb19tZXMsIGFlcyh4ID0gTWVzLCB5ID0gdG90YWwpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHRvdGFsKSksIHZqdXN0ID0gLTAuMjUsIHNpemUgPSAzKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBVdGVudGVzIGNvbSBIaXBlcnRlbnPDo28gcG9yIE3DqnMiLAogICAgICAgeCA9ICJNw6pzIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKCiMgSGlwZXJ0ZW5zw6NvIHBvciBtw6pzIC0gTWVub3MgZGUgNjUKaGlwZXJ0ZW5zYW9fbWVzXzY1IDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUoRGF0YV82NSA9IHltKHRlbXBvKSwKICAgICAgICAgTWVzXzY1ID0gbW9udGgoRGF0YV82NSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gRkFMU0UpKSAlPiUgIAogIGdyb3VwX2J5KE1lc182NSkgJT4lCiAgc3VtbWFyaXNlKGhpcF9tZW5vc182NSA9IHN1bShhcy5udW1lcmljKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24pLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBhcnJhbmdlKG1hdGNoKE1lc182NSwgbW9udGgubmFtZSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKZ2dwbG90KGhpcGVydGVuc2FvX21lc182NSwgYWVzKHggPSBNZXNfNjUsIHkgPSBoaXBfbWVub3NfNjUpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKGhpcF9tZW5vc182NSkpLCB2anVzdCA9IC0wLjI1LCBzaXplID0gMykgKwogIGxhYnModGl0bGUgPSAiVXRlbnRlcyA8NjUgYW5vcyBjb20gSGlwZXJ0ZW5zw6NvIHBvciBNw6pzIiwKICAgICAgIHggPSAiTcOqcyIsCiAgICAgICB5ID0gIlRvdGFsIGRlIFV0ZW50ZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCgojIFRhYmVsYSBkZSBtZXNlcyBlbSBwb3J0dWd1w6pzCm1lc2VzX3B0IDwtIGMoImphbmVpcm8iLCAiZmV2ZXJlaXJvIiwgIm1hcsOnbyIsICJhYnJpbCIsICJtYWlvIiwgImp1bmhvIiwgCiAgICAgICAgICAgICAgImp1bGhvIiwgImFnb3N0byIsICJzZXRlbWJybyIsICJvdXR1YnJvIiwgIm5vdmVtYnJvIiwgImRlemVtYnJvIikKCgptZXNfbG9va3VwIDwtIGMoCiAgImphbnVhcnkiID0gImphbmVpcm8iLCAiZmVicnVhcnkiID0gImZldmVyZWlybyIsICJtYXJjaCIgPSAibWFyw6dvIiwKICAiYXByaWwiID0gImFicmlsIiwgIm1heSIgPSAibWFpbyIsICJqdW5lIiA9ICJqdW5obyIsCiAgImp1bHkiID0gImp1bGhvIiwgImF1Z3VzdCIgPSAiYWdvc3RvIiwgInNlcHRlbWJlciIgPSAic2V0ZW1icm8iLAogICJvY3RvYmVyIiA9ICJvdXR1YnJvIiwgIm5vdmVtYmVyIiA9ICJub3ZlbWJybyIsICJkZWNlbWJlciIgPSAiZGV6ZW1icm8iCikKCgojIEp1bnRhciB0b3RhbCBlIDw2NSwgY2FsY3VsYXIgPj02NQpoaXBlcnRlbnNhb19jb21wX21lcyA8LSBoaXBlcnRlbnNhb19tZXMgJT4lCiAgbGVmdF9qb2luKGhpcGVydGVuc2FvX21lc182NSwgYnkgPSBjKCJNZXMiID0gIk1lc182NSIpKSAlPiUKICBtdXRhdGUoCiAgICBoaXBfbWVub3NfNjUgPSBpZmVsc2UoaXMubmEoaGlwX21lbm9zXzY1KSwgMCwgaGlwX21lbm9zXzY1KSwKICAgIGhpcF9tYWlzXzY1ID0gdG90YWwgLSBoaXBfbWVub3NfNjUsCiAgICBNZXMgPSBkcGx5cjo6cmVjb2RlKHRvbG93ZXIoYXMuY2hhcmFjdGVyKE1lcykpLCAhISFtZXNfbG9va3VwKSwKICAgIE1lcyA9IGZhY3RvcihNZXMsIGxldmVscyA9IG1lc2VzX3B0KQogICkgJT4lCiAgc2VsZWN0KE1lcywgaGlwX21lbm9zXzY1LCBoaXBfbWFpc182NSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoaGlwX21lbm9zXzY1LCBoaXBfbWFpc182NSksCiAgICBuYW1lc190byA9ICJHcm91cCIsCiAgICB2YWx1ZXNfdG8gPSAiVG90YWxfaGlwIgogICkgJT4lCiAgbXV0YXRlKAogICAgR3JvdXAgPSBkcGx5cjo6cmVjb2RlKEdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICJoaXBfbWVub3NfNjUiID0gIlVuZGVyIDY1IHllYXJzIG9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgImhpcF9tYWlzXzY1IiA9ICI2NSB5ZWFycyBvciBvbGRlciIpCiAgKQoKIyBHcsOhZmljbyBmaW5hbCAtIGJhcnJhcyBlZ3JvdXBfYnkoKSMgR3LDoWZpY28gZmluYWwgLSBiYXJyYXMgZW1waWxoYWRhcwpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fY29tcF9tZXMsIGFlcyh4ID0gTWVzLCB5ID0gVG90YWxfaGlwLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicygKICAgIHRpdGxlID0gIiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBieSBBZ2UgYW5kIE1vbnRoIiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJOdW1iZXIgb2YgcGF0aWVudHMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKYGBgCgpgYGB7cn0KCiMjIEFuw6FsaXNlIGRvIGRhdGFzZXQgYXZjOiAKCiNRdWFpcyBvcyBhbm9zIGUgbWVzZXMgw6kgcXVlIGVzdMOjbyByZWdpc3RhZG9zIG5vIEFWQwptZXNlc19wb3JfYW5vX2F2YyA8LSBhdmMgJT4lCiAgbXV0YXRlKEFub19hdmMgPSB5ZWFyKHltKFBlcsOtb2RvKSksCiAgICAgICAgIE1lc19hdmMgPSBtb250aCh5bShQZXLDrW9kbyksIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lCiAgZGlzdGluY3QoQW5vX2F2YywgTWVzX2F2YykgJT4lCiAgYXJyYW5nZShBbm9fYXZjLCBNZXNfYXZjKSAlPiUKICBncm91cF9ieShBbm9fYXZjKSAlPiUKICBzdW1tYXJpc2UoTWVzZXNfRGlzcG9uaXZlaXMgPSBwYXN0ZShNZXNfYXZjLCBjb2xsYXBzZSA9ICIsICIpKQoKI1ZlciBtaXNzaW5nIHZhbHVlcyAKc2FwcGx5KGF2YywgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpIHwgeCA9PSAiIikpCgojIERpc3RyaWJ1acOnw6NvIHBvciBHw6luZXJvIGNvbSBBVkMgCgphdmNfZ2VuZXJvIDwtIGF2YyAlPiUKICBncm91cF9ieShHw6luZXJvLmRhLlbDrXRpbWEpICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhUb3RhbF9BVkMpKQoKZ2dwbG90KGF2Y19nZW5lcm8sIGFlcyh4ID0gcmVvcmRlcihHw6luZXJvLmRhLlbDrXRpbWEsIC1Ub3RhbF9BVkMpLCB5ID0gVG90YWxfQVZDLCBmaWxsID0gR8OpbmVyby5kYS5Ww610aW1hKSkgKwogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBUb3RhbF9BVkMpLCB2anVzdCA9IC0wLjIsIHNpemUgPSAyKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIEfDqW5lcm8iLAogICAgICAgeCA9ICJHw6luZXJvIiwKICAgICAgIHkgPSAiVG90YWwgZGUgQVZDIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEaXN0cmlidWnDp8OjbyBwb3IgR8OpbmVybyBjb20gQVZDIGVtIGNhZGEgYW5vCgphdmNfZ2VuZXJvX2FubyA8LSBhdmMgJT4lCiAgbXV0YXRlKEFubyA9IHllYXIoeW0oUGVyw61vZG8pKSkgJT4lCiAgZ3JvdXBfYnkoQW5vLCBHw6luZXJvLmRhLlbDrXRpbWEpICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhOLsK6LmRlLnJlZ2lzdG9zLlZpYS5WZXJkZS5BVkMpLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBUcmFkdXppciB2YWxvcmVzIGRlICdHw6luZXJvLmRhLlbDrXRpbWEnCmF2YyRHw6luZXJvLmRhLlbDrXRpbWEgPC0gaWZlbHNlKGF2YyRHw6luZXJvLmRhLlbDrXRpbWEgPT0gIkZlbWluaW5vIiwgIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYXZjJEfDqW5lcm8uZGEuVsOtdGltYSA9PSAiTWFzY3VsaW5vIiwgIk1hbGUiLCBhdmMkR8OpbmVyby5kYS5Ww610aW1hKSkKCmdncGxvdChhdmNfZ2VuZXJvX2FubywgYWVzKHggPSBmYWN0b3IoQW5vKSwgeSA9IFRvdGFsX0FWQywgZmlsbCA9IEfDqW5lcm8uZGEuVsOtdGltYSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVG90YWxfQVZDKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuMjUsIHNpemUgPSAzKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyBieSBZZWFyIGFuZCBHZW5kZXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiVG90YWwgU3Ryb2tlIFJlY29yZHMiLAogICAgICAgZmlsbCA9ICJHZW5kZXIiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKIyBEaXN0cmlidWnDp8OjbyBwb3IgR8OpbmVybyBjb20gQVZDIGVtIGNhZGEgbcOqcwphdmNfZ2VuZXJvX21lcyA8LSBhdmMgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0oUGVyw61vZG8pLCAiJVktJW0iKSkgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgYEfDqW5lcm8uZGEuVsOtdGltYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpCgpnZ3Bsb3QoYXZjX2dlbmVyb19tZXMsIGFlcyh4ID0gTWVzX0FubywgeSA9IFRvdGFsX0FWQywgZmlsbCA9IGBHw6luZXJvLmRhLlbDrXRpbWFgKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnModGl0bGUgPSAiU3Ryb2tlIERpc3RyaWJ1dGlvbiBieSBNb250aCBhbmQgR2VuZGVyIiwKICAgICAgIHggPSAiTW9udGgiLCB5ID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIiwgZmlsbCA9ICJHZW5kZXIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyBEaXN0cmlidWnDp8OjbyBGYWl4YSBFdMOhcmlhIGNvbSBBVkMgbm8gdG90YWwgZG9zIGFub3MKCiMgRGVmaW5lIHRoZSBjb3JyZWN0IG9yZGVyIG9mIGFnZSByYW5nZXMKZmFpeGFfb3JkZW0gPC0gYygiMCAtIDE3IiwgIjE4IC0gMjkiLCAiMzAgLSAzOSIsICI0MCAtIDQ5IiwgIjUwIC0gNTkiLCAKICAgICAgICAgICAgICAgICAiNjAgLSA2OSIsICI3MCAtIDc5IiwgIjgwIC0gODkiLCAiOTAgLSA5OSIsICI+MTAwIikKCiMgQXBwbHkgdGhlIG9yZGVyIHVzaW5nIGZhY3RvcgphdmNfaWRhZGUgPC0gYXZjICU+JQogIGdyb3VwX2J5KGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYE4uwrouZGUucmVnaXN0b3MuVmlhLlZlcmRlLkFWQ2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCiMgUGxvdApnZ3Bsb3QoYXZjX2lkYWRlLCBhZXMoeCA9IGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgLCB5ID0gVG90YWxfQVZDKSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBUb3RhbF9BVkMpLCB2anVzdCA9IC0wLjIsIHNpemUgPSAyKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIEZhaXhhIEV0w6FyaWEiLAogICAgICAgeCA9ICJGYWl4YSBFdMOhcmlhIiwKICAgICAgIHkgPSAiVG90YWwgZGUgQVZDIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgRGlzdHJpYnVpw6fDo28gRmFpeGEgRXTDoXJpYSBjb20gQVZDIGVtIGNhZGEgYW5vCgphdmNfZmFpeGFfYW5vIDwtIGF2YyAlPiUKICBtdXRhdGUoQW5vID0geWVhcih5bShQZXLDrW9kbykpKSAlPiUKICBncm91cF9ieShBbm8sIGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYE4uwrouZGUucmVnaXN0b3MuVmlhLlZlcmRlLkFWQ2ApLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgbXV0YXRlKGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgID0gZmFjdG9yKGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgLCBsZXZlbHMgPSBmYWl4YV9vcmRlbSkpICU+JQogIGFycmFuZ2UoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWApCgoKZ2dwbG90KGF2Y19mYWl4YV9hbm8sIGFlcyh4ID0gZmFjdG9yKEFubyksIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIGJ5IFllYXIgYW5kIEFnZSBHcm91cCIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyIsCiAgICAgICBmaWxsID0gIkFnZSBHcm91cCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGlzdHJpYnVpw6fDo28gRmFpeGEgRXTDoXJpYSBjb20gQVZDIGVtIGNhZGEgbcOqcwoKYXZjX2ZhaXhhX21lcyA8LSBhdmMgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0oUGVyw61vZG8pLCAiJVktJW0iKSkgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JSBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCmdncGxvdChhdmNfZmFpeGFfbWVzLCBhZXMoeCA9IE1lc19Bbm8sIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlN0cm9rZSBEaXN0cmlidXRpb24gYnkgTW9udGggYW5kIEFnZSBHcm91cCIsCiAgICAgICB4ID0gIk1vbnRoIiwgeSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyIsIGZpbGwgPSAiQWdlIEdyb3VwZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIEfDqW5lcm8gw5cgRmFpeGEgRXTDoXJpYSBhbyBsb25nb3MgZG8gcGVyw61vZG8gCgphdmNfY3Jvc3MgPC0gYXZjICU+JQogIGdyb3VwX2J5KGBHw6luZXJvLmRhLlbDrXRpbWFgLCBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0FWQyA9IHN1bShhcy5udW1lcmljKGBOLsK6LmRlLnJlZ2lzdG9zLlZpYS5WZXJkZS5BVkNgKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JSBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCmdncGxvdChhdmNfY3Jvc3MsIGFlcyh4ID0gYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgR8OpbmVyby5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIGRlIEFWQyBwb3IgR8OpbmVybyBlIEZhaXhhIEV0w6FyaWEiLCB4ID0gIkZhaXhhIEV0w6FyaWEiLCB5ID0gIlRvdGFsIGRlIEFWQyIsIGZpbGwgPSAiR8OpbmVybyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKYGBge3J9CiMgQ29ycmVsYcOnw6NvIGVudHJlIEhpcGVydGVuc29zIGUgQVZDIHBvciBncnVwbyBldMOhcmlvIChtYWlvcmVzIGRlIDY1IGFub3MgZSBtZW5vcmVzIGRlIDY1IGFub3MpCgojIENsZWFuIG5hbWVzCmF2YyA8LSBhdmMgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCiMgRml4IGNvbHVtbiBuYW1lCm5hbWVzKGF2YylbbmFtZXMoYXZjKSA9PSAibl9vX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmMiXSA8LSAibl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjIgoKIyBEaXZpZGltb3MgbyBBVkMgZW0gbWFpb3JlcyBkZSA2NSBhbm9zIGUgbWVub3JlcyBkZSA2NSBhbm9zCmF2Y19jbGVhbiA8LSBhdmMgJT4lCiAgbXV0YXRlKAogICAgZmFpeGFfaW5pY2lvID0gYXMubnVtZXJpYyhzdHJfZXh0cmFjdChmYWl4YV9ldGFyaWFfZGFfdml0aW1hLCAiXlxcZCsiKSksCiAgICBmYWl4YV9maW0gPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KGZhaXhhX2V0YXJpYV9kYV92aXRpbWEsICJcXGQrJCIpKSwKICAgIEdyb3VwID0gY2FzZV93aGVuKAogICAgICBmYWl4YV9pbmljaW8gPCA2OSB+ICJVbmRlciA2NSB5ZWFycyBvbGQiLAogICAgICBUUlVFIH4gIjY1IHllYXJzIG9yIG9sZGVyIgogICAgKSwKICAgIG1lc19udW0gPSBhcy5pbnRlZ2VyKHN0cl9zdWIocGVyaW9kbywgNiwgNykpLAogICAgbWVzID0gZmFjdG9yKG1lc2VzX3B0W21lc19udW1dLCBsZXZlbHMgPSBtZXNlc19wdCksCiAgICBuX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmMgPSBhcy5udW1lcmljKG5fZGVfcmVnaXN0b3NfdmlhX3ZlcmRlX2F2YykKICApICU+JQogIGdyb3VwX2J5KG1lcywgR3JvdXApICU+JQogIHN1bW1hcmlzZSh0b3RhbF9hdmMgPSBzdW0obl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBGaWx0cmFyIGRhZG9zIGRlIGhpcGVydGVuc8OjbyBkZSAyMDIyLTAxIGEgMjAyNC0wMgpoeXBfZmlsdHJhZG8gPC0gaHlwX2ZpbmFsICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUKICBtdXRhdGUoRGF0YSA9IHltKHRlbXBvKSkgJT4lCiAgZmlsdGVyKERhdGEgPj0geW0oIjIwMjItMDEiKSAmIERhdGEgPD0geW0oIjIwMjQtMDIiKSkKCiMgSGlwZXJ0ZW5zw6NvIHRvdGFsIHBvciBtw6pzCmhpcGVydGVuc2FvX21lc19maWx0cmFkbyA8LSBoeXBfZmlsdHJhZG8gJT4lCiAgbXV0YXRlKE1lcyA9IG1vbnRoKERhdGEsIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lCiAgZ3JvdXBfYnkoTWVzKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oYXMubnVtZXJpYyh0b3RhbCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGFycmFuZ2UobWF0Y2goTWVzLCBtb250aC5uYW1lKSkKCiMgSGlwZXJ0ZW5zw6NvIGVtIG1lbm9yZXMgZGUgNjUgYW5vcwpoaXBlcnRlbnNhb19tZXNfNjVfZmlsdHJhZG8gPC0gaHlwX2ZpbHRyYWRvICU+JQogIG11dGF0ZShNZXMgPSBtb250aChEYXRhLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBGQUxTRSkpICU+JQogIGdyb3VwX2J5KE1lcykgJT4lCiAgc3VtbWFyaXNlKGhpcF82NSA9IHN1bShhcy5udW1lcmljKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24pLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBhcnJhbmdlKG1hdGNoKE1lcywgbW9udGgubmFtZSkpCgojIENvbWJpbmFyIGRhZG9zIGRlIGhpcGVydGVuc8OjbyBlIHByZXBhcmFyIGZvcm1hdG8gbG9uZ28KaGlwZXJ0ZW5zYW9fY29tcF9tZXNfZmlsdHJhZG8gPC0gaGlwZXJ0ZW5zYW9fbWVzX2ZpbHRyYWRvICU+JQogIGxlZnRfam9pbihoaXBlcnRlbnNhb19tZXNfNjVfZmlsdHJhZG8sIGJ5ID0gIk1lcyIpICU+JQogIG11dGF0ZSgKICAgIGhpcF82NSA9IGlmZWxzZShpcy5uYShoaXBfNjUpLCAwLCBoaXBfNjUpLAogICAgaGlwX21haXNfNjUgPSB0b3RhbCAtIGhpcF82NSwKICAgIE1lcyA9IG1lc19sb29rdXBbTWVzXSwKICAgIE1lcyA9IGZhY3RvcihNZXMsIGxldmVscyA9IG1lc2VzX3B0KQogICkgJT4lCiAgc2VsZWN0KE1lcywgaGlwXzY1LCBoaXBfbWFpc182NSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoImhpcF82NSIsICJoaXBfbWFpc182NSIpLAogICAgbmFtZXNfdG8gPSAiR3JvdXAiLAogICAgdmFsdWVzX3RvID0gIlRvdGFsX2hpcCIKICApICU+JQogIG11dGF0ZSgKICAgIEdyb3VwID0gZHBseXI6OnJlY29kZShHcm91cCwKICAgICAgImhpcF82NSIgPSAiVW5kZXIgNjUgeWVhcnMgb2xkIiwKICAgICAgImhpcF9tYWlzXzY1IiA9ICI2NSB5ZWFycyBvciBvbGRlciIpCiAgKQoKIyBHcsOhZmljbyBlbXBpbGhhZG8gZGUgaGlwZXJ0ZW5zw6NvCmdncGxvdChoaXBlcnRlbnNhb19jb21wX21lc19maWx0cmFkbywgYWVzKHggPSBNZXMsIHkgPSBUb3RhbF9oaXAsIGZpbGwgPSBHcm91cCkpICsKICBnZW9tX2NvbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSGlwZXJ0ZW5zw6NvIHBvciBJZGFkZSBlIE3DqnMgKDIwMjItMDEgYSAyMDI0LTAyKSIsCiAgICB4ID0gIk3DqnMiLAogICAgeSA9ICJOw7ptZXJvIGRlIFV0ZW50ZXMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCiMgUmVzdW1vIHBhcmEgYW7DoWxpc2UKaGlwZXJ0ZW5zYW9fc3VtbWFyeSA8LSBoaXBlcnRlbnNhb19jb21wX21lc19maWx0cmFkbyAlPiUKICBncm91cF9ieShNZXMsIEdyb3VwKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfSElQID0gc3VtKFRvdGFsX2hpcCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIHJlbmFtZShtZXMgPSBNZXMpCgojIE1lcmdlIGNvbSBkYWRvcyBkZSBBVkMKbWVyZ2VkIDwtIGxlZnRfam9pbihoaXBlcnRlbnNhb19zdW1tYXJ5LCBhdmNfY2xlYW4sIGJ5ID0gYygibWVzIiwgIkdyb3VwIikpCgojIEJveHBsb3RzIHBhcmEgdmlzdWFsaXphw6fDo28gZGUgb3V0bGllcnMKZ2dwbG90KG1lcmdlZCwgYWVzKHggPSBHcm91cCwgeSA9IFRvdGFsX0hJUCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90IG9mIENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIGJ5IEFnZSBHcm91cCIsIHg9Ikdyb3VwIiwgeT0iVG90YWwgSHlwZXJ0ZW5zaW9uIFBhdGllbnRzIikKCmdncGxvdChtZXJnZWQsIGFlcyh4ID0gR3JvdXAsIHkgPSB0b3RhbF9hdmMpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiQm94cGxvdCBvZiBTdHJva2UgQ2FzZXMgYnkgQWdlIEdyb3VwIiwgeD0iR3JvdXAiLCB5PSJUb3RhbCBTdHJva2UgQ2FzZXMiKQoKI2NvbW8gaMOhIG91dGxpZXJzLCBmYXplbW9zIGNvbSBvIHNwZWFybWFuCgojIENvcnJlbGHDp8OjbyBkZSBTcGVhcm1hbgpjb3JfcmVzdWx0c19zcGVhcm1hbiA8LSBtZXJnZWQgJT4lCiAgZ3JvdXBfYnkoR3JvdXApICU+JQogIHN1bW1hcmlzZShjb3JyZWwgPSBjb3IoVG90YWxfSElQLCB0b3RhbF9hdmMsIG1ldGhvZCA9ICJzcGVhcm1hbiIpKQoKcHJpbnQoY29yX3Jlc3VsdHNfc3BlYXJtYW4pCgojIFNjYXR0ZXJwbG90IGNvbSByZWdyZXNzw6NvIHBhcmEgdmlzdWFsaXphw6fDo28KZ2dwbG90KG1lcmdlZCwgYWVzKHggPSBUb3RhbF9ISVAsIHkgPSB0b3RhbF9hdmMsIGNvbG9yID0gR3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBmYWNldF93cmFwKH4gR3JvdXApICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBhbmQgU3Ryb2tlIGJ5IEFnZSBHcm91cCIsCiAgICB4ID0gIlRvdGFsIEh5cGVydGVuc2lvbiBQYXRpZW50cyIsCiAgICB5ID0gIlRvdGFsIFN0cm9rZSBDYXNlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkKCiMgUmVncmVzc8O1ZXMgbGluZWFyZXMgcG9yIGdydXBvCm1vZGVscyA8LSBtZXJnZWQgJT4lCiAgZ3JvdXBfYnkoR3JvdXApICU+JQogIGdyb3VwX21hcCh+IGxtKHRvdGFsX2F2YyB+IFRvdGFsX0hJUCwgZGF0YSA9IC54KSwgLmtlZXAgPSBUUlVFKQoKIyBSZXN1bW8gZGFzIHJlZ3Jlc3PDtWVzCnN1bW1hcnkobW9kZWxzW1sxXV0pICAjIFVuZGVyIDY1IHllYXJzIG9sZApzdW1tYXJ5KG1vZGVsc1tbMl1dKSAgIyA2NSB5ZWFycyBvciBvbGRlcgoKYGBgCgoKYGBge3J9CgojIFRvdGFsIGRlIFJlZ2lzdG9zIGRlIEFWQyBwb3IgRGlzdHJpdG8KYXZjX3JlZ2lhbyA8LSBhdmMgJT4lCiAgZ3JvdXBfYnkoYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYG5fZGVfcmVnaXN0b3NfdmlhX3ZlcmRlX2F2Y2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoVG90YWxfQVZDKSkgCgpnZ3Bsb3QoYXZjX3JlZ2lhbywgYWVzKHggPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgLVRvdGFsX0FWQyksIHkgPSBUb3RhbF9BVkMpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFRvdGFsX0FWQyksIHZqdXN0ID0gLTAuMiwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiRGlzdHJpY3QiLCB5ID0gIlBhdGllbnRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgRGlzdHJpYnVpw6fDo28gYW8gbG9uZ28gZG8gdGVtcG8gcG9yIGRpc3RyaXRvCgphdmNfcmVnaWFvX3RlbXBvIDwtIGF2YyAlPiUKICBtdXRhdGUoTWVzX0FubyA9IGZvcm1hdCh5bShwZXJpb2RvKSwgIiVZLSVtIikpICU+JQogIGdyb3VwX2J5KE1lc19Bbm8sIGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0FWQyA9IHN1bShhcy5udW1lcmljKGBuX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmNgKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikKCmdncGxvdChhdmNfcmVnaWFvX3RlbXBvLCBhZXMoeCA9IE1lc19Bbm8sIHkgPSBUb3RhbF9BVkMsIGNvbG9yID0gYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgLCBncm91cCA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIE1lbnNhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiTcOqcyIsIHkgPSAiVG90YWwgZGUgQVZDIiwgY29sb3IgPSAiRGlzdHJpdG8iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyMgSXIgYnVzY2FyIG8gbsO6bWVybyBkZSBoYWJpdGFudGVzIHBvciBkaXN0cml0byBlbSBwb3J0dWdhbCBlbSAyMDIyLCAyMDIzIGUgMjAyNCBlIGZhemVyIG3DqWRpYSwgcGFyYSBub3JtYWxpemFyIGUgcG9kZXIgY29tcGFyYXIsIHBvcnF1ZSBvYnZpYW1lbnRlIHF1ZSBubyBwb3J0byBlIGxpc2JvYSBow6EgbWFpb3IgbnVtZXJvIGRlIGF2YyBwb3JxdWUgaMOhIG1haXMgaGFiaXRhbnRlcy4KCiMgVmV0b3IgY29tIGFzIHBvcHVsYcOnw7VlcyBtw6lkaWFzIGVzdGltYWRhcwpwb3B1bGFjYW9fZGlzdHJpdG9zIDwtIGMoCiAgIkxpc2JvYSIgPSAyMzE4OTUyLAogICJQb3J0byIgPSAxODI5NzU4LAogICJTZXTDumJhbCIgPSA4OTM0NjQsCiAgIkJyYWdhIiA9IDg1ODcwOCwKICAiQXZlaXJvIiA9IDcxNzk5OCwKICAiRmFybyIgPSA0NzQ1MDAsCiAgIkxlaXJpYSIgPSA0NzE1NzAsCiAgIlNhbnRhcsOpbSIgPSA0MzY4OTEsCiAgIkNvaW1icmEiID0gNDEzMjI1LAogICJWaXNldSIgPSAzNjQwMjAsCiAgIk1hZGVpcmEiID0gMjU0NjMwLAogICJBw6dvcmVzIiA9IDI0MTQ3MSwKICAiVmlhbmEgZG8gQ2FzdGVsbyIgPSAyMzM2MTAsCiAgIlZpbGEgUmVhbCIgPSAxODUyNjMsCiAgIkNhc3RlbG8gQnJhbmNvIiA9IDE3ODg2MCwKICAiw4l2b3JhIiA9IDE1MzQyNywKICAiQmVqYSIgPSAxNDczNjMsCiAgIkd1YXJkYSIgPSAxNDIxMzEsCiAgIkJyYWdhbsOnYSIgPSAxMjMxMDksCiAgIlBvcnRhbGVncmUiID0gMTA0NTYxCikKCgojIEFkaWNpb25hciBwb3B1bGHDp8OjbyBhbyBEYXRhRnJhbWUKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIG11dGF0ZShQb3B1bGFjYW8gPSBwb3B1bGFjYW9fZGlzdHJpdG9zW2BkaXN0cml0b19kYV9vY29ycmVuY2lhYF0sCiAgICAgICAgIFRheGFfQVZDID0gKFRvdGFsX0FWQyAvIFBvcHVsYWNhbykgKiAxMDAwMDApCgojIE3DqWRpYSBkYSB0YXhhIGRlIEFWQyBwb3IgZGlzdHJpdG8KcmFua2luZ19kaXN0cml0b3MgPC0gYXZjX3JlZ2lhb190ZW1wbyAlPiUKICBncm91cF9ieShgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0FWQyA9IG1lYW4oVGF4YV9BVkMsIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhNZWRpYV9UYXhhX0FWQykpCgpwcmludChyYW5raW5nX2Rpc3RyaXRvcykKCmdncGxvdChyYW5raW5nX2Rpc3RyaXRvcywgYWVzKHggPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgTWVkaWFfVGF4YV9BVkMpLCB5ID0gTWVkaWFfVGF4YV9BVkMpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJkYXJrcmVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChNZWRpYV9UYXhhX0FWQywgMSkpLCBoanVzdCA9IC0wLjEsIHNpemUgPSAzKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiRGlzdHJpY3QiLCB5ID0gIlJhdGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIFZpc3VhbGl6YXIgYXMgdGF4YXMgZGUgQVZDIGFvIGxvbmdvIGRvIHRlbXBvIHBvciBkaXN0cml0bwpnZ3Bsb3QoYXZjX3JlZ2lhb190ZW1wbywgYWVzKHggPSBNZXNfQW5vLCB5ID0gVGF4YV9BVkMsIGNvbG9yID0gYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgLCBncm91cCA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIE1lbnNhbCBkYSBUYXhhIGRlIEFWQyBwb3IgRGlzdHJpdG8iLAogICAgICAgeCA9ICJNw6pzIiwgeSA9ICJUYXhhIGRlIEFWQyBwb3IgMTAwLjAwMCBoYWJpdGFudGVzIiwgY29sb3IgPSAiRGlzdHJpdG8iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKI0NvbW8gbsOjbyDDqSBwb3NzaXZlbCBjb21wYXJhciBiZW0gcGVsbyBncsOhZmljbywgdmFtb3MgZmF6ZXIgdGVzdGVzIGVzdGF0aXRpc3RpY29zLiAKCiN2YW1vcyB2ZXIgcHJpbWVpcm8gc2UgbyB0b3RhbF9hdmMgdGVtIGRpc3RyaWJ1acOnw6NvIG5vcm1hbCBlbSB0b2RvcyBvcyBkaXN0cml0b3MKCmdncGxvdChhdmNfcmVnaWFvX3RlbXBvLCBhZXMoeCA9IFRheGFfQVZDKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCh+IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIEFwbGljYXIgbyB0ZXN0ZSBzaGFwaXJvIApzaGFwaXJvX3Jlc3VsdHMgPC0gYXZjX3JlZ2lhb190ZW1wbyAlPiUKICBncm91cF9ieShkaXN0cml0b19kYV9vY29ycmVuY2lhKSAlPiUKICBzdW1tYXJpc2UocF92YWx1ZSA9IHNoYXBpcm8udGVzdChUYXhhX0FWQykkcC52YWx1ZSkKCiMgUHJpbnQKcHJpbnQoc2hhcGlyb19yZXN1bHRzKQoKIyBIb21vZ2VuZWlkYWRlIGRhcyB2YXJpw6JuY2lhcyBlbnRyZSBvcyBncnVwb3MKCmxldmVuZV9yZXN1bHQgPC0gbGV2ZW5lVGVzdChUYXhhX0FWQyB+IGRpc3RyaXRvX2RhX29jb3JyZW5jaWEsIGRhdGEgPSBhdmNfcmVnaWFvX3RlbXBvKQoKIyBQcmludGFyIG8gcmVzdWx0YWRvCnByaW50KGxldmVuZV9yZXN1bHQpCgojY29uY2x1c8Ojbzogb3MgZGFkb3Mgc8OjbyBkaXN0cmlidWlkb3Mgbm9ybWFsbWVudGUgZSBhcyB2YXJpw6JuY2lhcyBzw6NvIHNpZ25pZmljYXRpdmFtZW50ZSBkaWZlcmVudGVzLiBMb2dvLCB2YW1vcyBmYXplciBvIHRlc3RlIFdlbGNoIEFOT1ZBIChvbmV3YXkudGVzdCkgcGFyYSBjb21wYXJhciBhcyBtw6lkaWFzIGRhcyB0YXhhcyBkZSBBVkMgcG9yIDEwMC4wMDAgaGFiaXRhbnRlcyBlbnRyZSBkaXN0cml0b3MsIHNlbSBhc3N1bWlyIHZhcmnDom5jaWFzIGlndWFpcy4KCiMgV2VsY2ggQU5PVkEKb25ld2F5LnRlc3QoVGF4YV9BVkMgfiBgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWAsIGRhdGEgPSBhdmNfcmVnaWFvX3RlbXBvLCB2YXIuZXF1YWwgPSBGQUxTRSkKCiN2YW1vcyB2ZXIgY29tbyBhIHRheGEgbcOpZGlhIGRlIEFWQyBldm9sdWl1IGFvIGxvbmdvIGRvcyBhbm9zIHBvciBkaXN0cml0bwoKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIG11dGF0ZShBbm8gPSBzdWJzdHIoTWVzX0FubywgMSwgNCkpICAjIGV4dHJhaSBvcyA0IHByaW1laXJvcyBjYXJhY3RlcmVzIGNvbW8gYW5vCgptZWRpYV9hbnVhbF9kaXN0cml0byA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIGdyb3VwX2J5KEFubywgYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgKSAlPiUKICBzdW1tYXJpc2UoTWVkaWFfVGF4YV9BVkMgPSBtZWFuKFRheGFfQVZDLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKZ2dwbG90KG1lZGlhX2FudWFsX2Rpc3RyaXRvLCBhZXMoeCA9IEFubywgeSA9IE1lZGlhX1RheGFfQVZDLCBjb2xvciA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgZ3JvdXAgPSBgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIEFudWFsIGRhIFRheGEgZGUgQVZDIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIkFubyIsCiAgICAgICB5ID0gIlRheGEgbcOpZGlhIGRlIEFWQyBwb3IgMTAwLjAwMCBoYWJpdGFudGVzIiwKICAgICAgIGNvbG9yID0gIkRpc3RyaXRvIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgIEhlYXRtYXAgCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgLU1lZGlhX1RheGFfQVZDKSkpICsKICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBNZWRpYV9UYXhhX0FWQyksIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJIZWF0IE1hcDogU3Ryb2tlIFJhdGUgYnkgRGlzdHJpY3QgYW5kIFllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiRGlzdHJpY3QiLAogICAgICAgZmlsbCA9ICJSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpgYGB7cn0KCiMjIEEgbWVzbWEgYW7DoWxpc2UgbWFzIHBhcmEgaGlwZXJ0ZW5zb3MgCiMgMS4gRGFkb3MgbWVuc2FpcyBmaWx0cmFkb3MgKDIwMjItMDEgYSAyMDI0LTAyKQpoaXBlcnRlbnNhb190ZW1wbyA8LSBoeXBfZmluYWwgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0odGVtcG8pLCAiJVktJW0iKSkgJT4lCiAgZmlsdGVyKE1lc19Bbm8gPj0gIjIwMjItMDEiLCBNZXNfQW5vIDw9ICIyMDI0LTAyIikgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgZGlzdHJpdG9zLngpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oYXMubnVtZXJpYyh0b3RhbCksbmEucm0gPSBUUlVFKSwKICAgIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZSggUG9wdWxhY2FvID0gcG9wdWxhY2FvX2Rpc3RyaXRvc1tkaXN0cml0b3MueF0sCiAgICAgICAgICBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSAoVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSAvIFBvcHVsYWNhbykgKiAxMDAwMDAKICApJT4lCiAgc3RfZHJvcF9nZW9tZXRyeShoaXBlcnRlbnNhb190ZW1wbyklPiUKICByZW5hbWUoRGlzdHJpdG8gPSBkaXN0cml0b3MueCkKCiMgMi4gVG90YWwgYWN1bXVsYWRvIHBvciBkaXN0cml0bwpoaXBlcnRlbnNhb190b3RhbCA8LSBoaXBlcnRlbnNhb190ZW1wbyAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpKQoKCiMgR3LDoWZpY28gZGUgdG90YWwgYWN1bXVsYWRvCmdncGxvdChoaXBlcnRlbnNhb190b3RhbCwgYWVzKHggPSByZW9yZGVyKERpc3RyaXRvLCAtVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSksIHkgPSBUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhKSksIHZqdXN0ID0gLTAuMiwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFBhdGllbnRzIHdpdGggQ29udHJvbGxlZCBIeXBlcnRlbnNpb24gYnkgRGlzdHJpY3QiLAogICAgICAgeCA9ICJEaXN0cmljdCIsIHkgPSAiUGF0aWVudHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKCiMgRGlzdHJpYnVpw6fDo28gYW8gbG9uZ28gZG8gdGVtcG8gcG9yIGRpc3RyaXRvCgpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gTWVzX0FubywgeSA9IFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGNvbG9yID0gYERpc3RyaXRvYCwgZ3JvdXAgPSBgRGlzdHJpdG9gKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIkV2b2x1w6fDo28gTWVuc2FsIGRlIFJlZ2lzdG9zIGRlIGhpcGVydGVuc2FvIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIk3DqnMiLCB5ID0gIlRvdGFsIGRlIEhpcGVydGVuc8OjbyIsIGNvbG9yID0gIkRpc3RyaXRvIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCgojIDMuIEdyw6FmaWNvIGRlIGV2b2x1w6fDo28gbWVuc2FsIGRhcyB0YXhhcwpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gTWVzX0FubywgeSA9IFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgY29sb3IgPSBEaXN0cml0bywgZ3JvdXAgPSBEaXN0cml0bykpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIG1lbnNhbCBkYSBUYXhhIGRlIEhpcGVydGVuc8OjbyBDb250cm9sYWRhIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIk3DqnMiLCB5ID0gIlRheGEgZGUgSGlwZXJ0ZW5zw6NvIHBvciAxMDAuMDAwIGhhYml0YW50ZXMiLCBjb2xvciA9ICJEaXN0cml0byIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMQogICkpCgoKIyA0LiBNw6lkaWEgZGEgdGF4YSBwb3IgZGlzdHJpdG8KcmFua2luZ19kaXN0cml0b3MgPC0gaGlwZXJ0ZW5zYW9fdGVtcG8gJT4lCiAgZ3JvdXBfYnkoRGlzdHJpdG8pICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBtZWFuKFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSkpCgojIEdyw6FmaWNvIGRlIHJhbmtpbmcgZGFzIHRheGFzIG3DqWRpYXMKZ2dwbG90KHJhbmtpbmdfZGlzdHJpdG9zLCBhZXMoeCA9IHJlb3JkZXIoRGlzdHJpdG8sIE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSksIHkgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJkYXJrZ3JlZW4iKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgMSkpLCBoanVzdCA9IC0wLjEsIHNpemUgPSAyKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIkNvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYnkgRGlzdHJpY3QiLAogICAgICAgeCA9ICJEaXN0cmljdCIsIHkgPSAiUmF0ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCgojIDUuIEhpc3RvZ3JhbWFzIHBvciBkaXN0cml0byAoZGlzdHJpYnVpw6fDo28gZGFzIHRheGFzKQpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCh+IERpc3RyaXRvLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgNi4gVGVzdGUgZGUgbm9ybWFsaWRhZGUgKFNoYXBpcm8tV2lsaykKc2hhcGlyb19yZXN1bHRzIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UocF92YWx1ZSA9IHNoYXBpcm8udGVzdChUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpJHAudmFsdWUpCgpwcmludChzaGFwaXJvX3Jlc3VsdHMpCgojIDcuIFRlc3RlIGRlIGhvbW9nZW5laWRhZGUgZGFzIHZhcmnDom5jaWFzIChMZXZlbmUpCmxldmVuZVRlc3QoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gRGlzdHJpdG8sIGRhdGEgPSBoaXBlcnRlbnNhb190ZW1wbykKIAprcnVza2FsLnRlc3QoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gRGlzdHJpdG8sIGRhdGEgPSBoaXBlcnRlbnNhb190ZW1wbykKCiMgUGFydGluZG8gZG8gb2JqZXRvIGBoaXBlcnRlbnNhb190ZW1wb2AgasOhIGV4aXN0ZW50ZSBlIGZpbHRyYWRvICgyMDIyLTIwMjQpCgojIDEuIEV4dHJhaXIgbyBhbm8KaGlwZXJ0ZW5zYW9fdGVtcG8gPC0gaGlwZXJ0ZW5zYW9fdGVtcG8gJT4lCiAgbXV0YXRlKEFubyA9IHN1YnN0cihNZXNfQW5vLCAxLCA0KSkKCiMgMi4gQ2FsY3VsYXIgbcOpZGlhIGFudWFsIGRhIHRheGEgcG9yIGRpc3RyaXRvCm1lZGlhX2FudWFsX2Rpc3RyaXRvIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KEFubywgRGlzdHJpdG8pICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBtZWFuKFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikKCiMgMy4gR3LDoWZpY28gZGUgbGluaGFzOiBFdm9sdcOnw6NvIGFudWFsCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGNvbG9yID0gRGlzdHJpdG8sIGdyb3VwID0gRGlzdHJpdG8pKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIEFudWFsIGRhIFRheGEgZGUgSGlwZXJ0ZW5zw6NvIENvbnRyb2xhZGEgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVGF4YSBtw6lkaWEgcG9yIDEwMC4wMDAgaGFiaXRhbnRlcyIsCiAgICAgICBjb2xvciA9ICJEaXN0cml0byIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIDQuIEhlYXRtYXA6IE1hcGEgZGUgY2Fsb3IgcG9yIGRpc3RyaXRvIGUgYW5vCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSByZW9yZGVyKERpc3RyaXRvLCAtTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkpICsKICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAiZGFya2dyZWVuIikgKwogIGxhYnModGl0bGUgPSAiSGVhdCBNYXA6IENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYnkgRGlzdHJpY3QgYW5kIFllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiRGlzdHJpY3QiLAogICAgICAgZmlsbCA9ICJSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKQoKI1ZhbW9zIGFqdXN0YXIgdW1hIHJlZ3Jlc3PDo28gbGluZWFyIGRhIHRheGEgbcOpZGlhIGFudWFsIHZzIGFubyBwYXJhIGNhZGEgZGlzdHJpdG8gZSB2ZXIgbyBjb2VmaWNpZW50ZSBkYSBpbmNsaW5hw6fDo286IAojIENvbnZlcnRlciBvIGFubyBwYXJhIG51bcOpcmljbwptZWRpYV9hbnVhbF9kaXN0cml0byRBbm9fTnVtIDwtIGFzLm51bWVyaWMobWVkaWFfYW51YWxfZGlzdHJpdG8kQW5vKQoKIyBSZWdyZXNzw6NvIGxpbmVhciBwb3IgZGlzdHJpdG8KdGVuZGVuY2lhcyA8LSBtZWRpYV9hbnVhbF9kaXN0cml0byAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKAogICAgaW5jbGluYWNhbyA9IGNvZWYobG0oTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gQW5vX051bSkpWzJdLAogICAgcF92YWxvciA9IHN1bW1hcnkobG0oTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gQW5vX051bSkpJGNvZWZmaWNpZW50c1syLCA0XQogICkgJT4lCiAgYXJyYW5nZShpbmNsaW5hY2FvKQoKcHJpbnQodGVuZGVuY2lhcykKCiMgQXBsaWNhIG8gdGVzdGUgZGUgTWFubi1LZW5kYWxsIGdsb2JhbG1lbnRlCm1rLnRlc3QobWVkaWFfYW51YWxfZGlzdHJpdG8kTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKQoKbW9kZWxvX2dsb2JhbCA8LSBsbShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgfiBBbm9fTnVtLCBkYXRhID0gbWVkaWFfYW51YWxfZGlzdHJpdG8pCnN1bW1hcnkobW9kZWxvX2dsb2JhbCkKYGBgCgpgYGB7cn0KCiMjIENPTVBBUkHDh8ODTyBDT00gQVMgVEFYQVMgTk9TIEFOT1MgQ09NVU5TCgojIEFWQwphdmNfcmVnaWFvIDwtIGF2YyAlPiUKICBncm91cF9ieShgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgbl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjYCksIG5hLnJtID0gVFJVRSkpICU+JQogIHJlbmFtZShEaXN0cml0byA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkKCiMgSGlwZXJ0ZW5zw6NvCmhpcGVydGVuc2FvX3RvdGFsIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IHN1bShUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBuYS5ybSA9IFRSVUUpKSAKCiMgSnVudGFyCmRmX3JlbGFjYW8gPC0gZnVsbF9qb2luKGF2Y19yZWdpYW8sIGhpcGVydGVuc2FvX3RvdGFsLCBieSA9ICJEaXN0cml0byIpICU+JQogIG11dGF0ZSgKICAgIFBvcHVsYWNhbyA9IHBvcHVsYWNhb19kaXN0cml0b3NbRGlzdHJpdG9dLAogICAgVGF4YV9BVkMgPSAoVG90YWxfQVZDIC8gUG9wdWxhY2FvKSAqIDEwMDAwMCwKICAgIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhIC8gUG9wdWxhY2FvKSAqIDEwMDAwMAogICkgJT4lCiAgZHJvcF9uYSgpCmdncGxvdChkZl9yZWxhY2FvLCBhZXMoeCA9IFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgeSA9IFRheGFfQVZDKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya2JsdWUiLCBzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgY29sb3IgPSAicmVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBEaXN0cml0byksIHZqdXN0ID0gLTAuOCwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYW5kIFN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiQ29udHJvbGxlZCBIeXBlcnRlbnNpb24gUmF0ZSBwZXIgMTAwLDAwMCBpbmhhYml0YW50cyIsCiAgICAgICB5ID0gIlN0cm9rZSBSYXRlIHBlciAxMDAsMDAwIGluaGFiaXRhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyB2ZXIgc2UgdGVuaG8gb3V0bGllcnMgCgpib3hwbG90KGRmX3JlbGFjYW8kVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLAogICAgICAgIG1haW4gPSAiQm94cGxvdCBvZiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgICB5bGFiID0gIlJhdGUiKQoKIyBCb3hwbG90IGZvciBTdHJva2UgUmF0ZQpib3hwbG90KGRmX3JlbGFjYW8kVGF4YV9BVkMsCiAgICAgICAgbWFpbiA9ICJCb3hwbG90IG9mIFN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgICB5bGFiID0gIlJhdGUiKQoKIyBQYXJhIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYQp4IDwtIGRmX3JlbGFjYW8kVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhClExIDwtIHF1YW50aWxlKHgsIDAuMjUsIG5hLnJtID0gVFJVRSkKUTMgPC0gcXVhbnRpbGUoeCwgMC43NSwgbmEucm0gPSBUUlVFKQpJUVIgPC0gUTMgLSBRMQoKIyBMaW1pdGVzIGluZmVyaW9yIGUgc3VwZXJpb3IKbGltX2luZiA8LSBRMSAtIDEuNSAqIElRUgpsaW1fc3VwIDwtIFEzICsgMS41ICogSVFSCgojIFZlciBxdWFpcyBzw6NvIG9zIG91dGxpZXJzCm91dGxpZXJzIDwtIHhbeCA8IGxpbV9pbmYgfCB4ID4gbGltX3N1cF0KcHJpbnQob3V0bGllcnMpCgojTsOjbyB0ZW0gb3V0bGllcnMKIwojIENvcnJlbGHDp8Ojbwpjb3IudGVzdChkZl9yZWxhY2FvJFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgZGZfcmVsYWNhbyRUYXhhX0FWQywgbWV0aG9kID0gInBlYXJzb24iKQoKCiMgUmVncmVzc8OjbwpzdW1tYXJ5KGxtKFRheGFfQVZDIH4gVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBkYXRhID0gZGZfcmVsYWNhbykpCmBgYAoKYGBge3J9CgojIEp1bnRhciBwb3IgRGlzdHJpdG8gZSBNw6pzCgoKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIHJlbmFtZShEaXN0cml0byA9IGRpc3RyaXRvX2RhX29jb3JyZW5jaWEpCgoKZGFkb3NfbWVuc2Fpc19jb21iaW5hZG9zIDwtIGlubmVyX2pvaW4oYXZjX3JlZ2lhb190ZW1wbywgaGlwZXJ0ZW5zYW9fdGVtcG8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiTWVzX0FubyIsICJEaXN0cml0byIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWZmaXggPSBjKCJfQVZDIiwgIl9IaXBlcnRlbnNhbyIpKSAlPiUKICBzZWxlY3QoTWVzX0FubywgRGlzdHJpdG8sIFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpCgojIENvcnJlbGFjzKdhzINvIGRlIFBlYXJzb24gcG9yIGRpc3RyaXRvCmNvcnJlbGFjb2VzX2Rpc3RyaXRvIDwtIGRhZG9zX21lbnNhaXNfY29tYmluYWRvcyAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKAogICAgY29ycmVsYWNhbyA9IGNvcihUYXhhX0FWQywgVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCB1c2UgPSAiY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApICU+JQogIGFycmFuZ2UoY29ycmVsYWNhbykKCnByaW50KGNvcnJlbGFjb2VzX2Rpc3RyaXRvKQoKZ2dwbG90KGNvcnJlbGFjb2VzX2Rpc3RyaXRvLCBhZXMoeCA9IHJlb3JkZXIoRGlzdHJpdG8sIGNvcnJlbGFjYW8pLCB5ID0gY29ycmVsYWNhbykpICsKICBnZW9tX2NvbChmaWxsID0gInB1cnBsZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoY29ycmVsYWNhbywgMikpLCBoanVzdCA9IC0wLjIsIHNpemUgPSAzKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIkNvcnJlbGHDp8OjbyBlbnRyZSBUYXhhIGRlIEFWQyBlIEhpcGVydGVuc8OjbyBDb250cm9sYWRhIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIkRpc3RyaXRvIiwgeSA9ICJDb3JyZWxhw6fDo28gKHIpIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBKdW50YXIgb3MgZGFkb3MgbWVuc2FpcwpkYWRvc19tZW5zYWlzX2NvbWJpbmFkb3MgPC0gaW5uZXJfam9pbihhdmNfcmVnaWFvX3RlbXBvLCBoaXBlcnRlbnNhb190ZW1wbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJNZXNfQW5vIiwgIkRpc3RyaXRvIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeCA9IGMoIl9BVkMiLCAiX0hpcGVydGVuc2FvIikpICU+JQogIHNlbGVjdChNZXNfQW5vLCBEaXN0cml0bywgVGF4YV9BVkMsIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSkKCiMgQ2FsY3VsYXIgY29ycmVsYcOnw6NvIGUgcC12YWxvciBwb3IgZGlzdHJpdG8KY29ycmVsYWNvZXNfZGlzdHJpdG8gPC0gZGFkb3NfbWVuc2Fpc19jb21iaW5hZG9zICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UoCiAgICByID0gY29yKFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpLAogICAgcF92YWx1ZSA9IGNvci50ZXN0KFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpJHAudmFsdWUsCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICBhcnJhbmdlKHIpCgojIFZlciBkaXN0cml0b3MgY29tIGNvcnJlbGHDp8OjbyBuZWdhdGl2YSBzaWduaWZpY2F0aXZhCmNvcnJlbGFjb2VzX3NpZ25pZmljYXRpdmFzIDwtIGNvcnJlbGFjb2VzX2Rpc3RyaXRvICU+JQogIGZpbHRlcihyIDwgLTAuMywgcF92YWx1ZSA8IDAuMDUpCgpwcmludChjb3JyZWxhY29lc19zaWduaWZpY2F0aXZhcykKCmdncGxvdChjb3JyZWxhY29lc19kaXN0cml0bywgYWVzKHggPSByZW9yZGVyKERpc3RyaXRvLCByKSwgeSA9IHIsIGZpbGwgPSBwX3ZhbHVlIDwgMC4wNSAmIHIgPCAtMC4zKSkgKwogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIGhqdXN0ID0gLTAuMiwgc2l6ZSA9IDMpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk3MCIsICJkYXJrcmVkIiksIGxhYmVscyA9IGMoIk7Do28gc2lnbmlmaWNhdGl2YSIsICJTaWduaWZpY2F0aXZhIiksIG5hbWUgPSAiQ29ycmVsYcOnw6NvIG5lZ2F0aXZhIHNpZ25pZmljYXRpdmEiKSArCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhw6fDo28gZW50cmUgSGlwZXJ0ZW5zw6NvIENvbnRyb2xhZGEgZSBBVkMgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiRGlzdHJpdG8iLCB5ID0gIkNvZWZpY2llbnRlIGRlIENvcnJlbGHDp8OjbyAocikiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKYGBgCgoKYGBge3J9CiMgQ29ycmVsYcOnw6NvIGVudHJlIGhpcGVydGVuw6fDo28gZSBhdmMgY29tIGFzIHRheGFzCiMgQ29uc2lkZXJhbmRvIG8gbWFpb3IgcGVyw61vZG8gZGUgdGVtcG8gZGFkbyBwZWxhIGRhdGEKCiNwb3B1bGHDp8OjbyBtw6lkaWEgcHIgZGlzdHJpdG9zIGVudHJlIDIwMTUgZSAyMDIzCnBvcHVsYWNhb19tZWRpYSA8LSBjKAogIExpc2JvYSA9IDIyNzYyOTMsCiAgUG9ydG8gPSAxNzk1NTQ5LAogIFNldHViYWwgPSA4Njk3NzAsCiAgQnJhZ2EgPSA4NDM2OTcsCiAgQXZlaXJvID0gNzAzMDIyLAogIEZhcm8gPSA0NjI1MjIsCiAgTGVpcmlhID0gNDU3MjQyLAogIFNhbnRhcmVtID0gNDM3NTIwLAogIENvaW1icmEgPSA0MTE5MzUsCiAgVmlzZXUgPSAzNjIyNzUsCiAgTWFkZWlyYSA9IDI1MTAyNSwKICBBY29yZXMgPSAyMzgxMjcsCiAgVmlhbmFfZG9fQ2FzdGVsbyA9IDIzNDY3MiwKICBWaWxhX1JlYWwgPSAxOTU0MjIsCiAgQ2FzdGVsb19CcmFuY28gPSAxODM5OTYsCiAgRXZvcmEgPSAxNTU0NDEsCiAgQmVqYSA9IDE0NDc3MiwKICBHdWFyZGEgPSAxNDg5MzIsCiAgQnJhZ2FuY2EgPSAxMjczNTYsCiAgUG9ydGFsZWdyZSA9IDEwOTk3NQopCgpoaXBlcnRlbnNhb190ZW1wb19hbGwgPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZShNZXNfQW5vID0gZm9ybWF0KHltKHRlbXBvKSwgIiVZLSVtIikpICU+JQogIGdyb3VwX2J5KE1lc19Bbm8sIGRpc3RyaXRvcy54KSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhID0gc3VtKGFzLm51bWVyaWModG90YWwpLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lCiAgbXV0YXRlKAogICAgUG9wdWxhY2FvID0gcG9wdWxhY2FvX21lZGlhW2Rpc3RyaXRvcy54XSwKICAgIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhIC8gcG9wdWxhY2FvX21lZGlhKSAqIDEwMDAwMAogICkKCgoKaGlwZXJ0ZW5zYW9fdG90YWxfMjAxNSA8LSBoaXBlcnRlbnNhb190ZW1wb19hbGwgJT4lCiAgZ3JvdXBfYnkoZGlzdHJpdG9zLngpICU+JQogIHN1bW1hcmlzZShUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSklPiUKICByZW5hbWUoRGlzdHJpdG8gPSBkaXN0cml0b3MueCkKCgphdmNfaGlwZXJ0ZW5zYW9fYWxsIDwtIGF2Y19yZWdpYW9fdGVtcG8gJT4lCiAgaW5uZXJfam9pbihoaXBlcnRlbnNhb190b3RhbF8yMDE1LCBieSA9ICJEaXN0cml0byIpCgpnZ3Bsb3QoYXZjX2hpcGVydGVuc2FvX2FsbCwgYWVzKHggPSBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHkgPSBUYXhhX0FWQykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAzKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBSYXRlIGFuZCBTdHJva2UgUmF0ZSBieSBEaXN0cmljdCIsCiAgICAgICB4ID0gIkNvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgZnJvbSAyMDE1IHRvIDIwMjQiLAogICAgICAgeSA9ICJTdHJva2UgUmF0ZSBmcm9tIDIwMjIgdG8gMjAyNCIpICsKICB0aGVtZV9taW5pbWFsKCkKCmNvcnJlbGFjYW8gPC0gY29yKGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW9fYWxsJFRheGFfQVZDKQpwcmludChjb3JyZWxhY2FvKQoKCiNUZXN0ZXMgbsOjbyBwYXJhbcOpdHJpY29zCiNjb3JyZWxhw6fDo28gZGUgc3BlYXJtYW4gLSBtb27Ds3RvbmEgbsOjbyBsaW5lYXIKYyA8LSBjb3IoYXZjX2hpcGVydGVuc2FvX2FsbCRUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9BVkMsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCnByaW50KGMpCgojIG1lZGlkYSBuw6NvIHBhcmFtw6l0cmljYSBxdWUgYXZhbGlhIGEgYXNzb2NpYcOnw6NvIG1vbm90w7RuaWNhIGVudHJlIGR1YXMgdmFyacOhdmVpcy4gT3Ugc2VqYSwgdmVyaWZpY2Egc2UsIMOgIG1lZGlkYSBxdWUgdW1hIHZhcmnDoXZlbCBhdW1lbnRhLCBhIG91dHJhIHRlbmRlIGEgYXVtZW50YXIgKG91IGRpbWludWlyKSwgc2VtIGV4aWdpciB1bWEgcmVsYcOnw6NvIGxpbmVhci4KI2V4aXN0ZSB1bWEgY29ycmVsYcOnw6NvIG5lYWd0aXZhIGZyYWNhICgtMC4yMTI1NzA0KSBlbnRyZSBhcyBkdWFzIHZhcmnDoXZlaXMKCgojY29yZWVsYcOnw6NvIGRlIGtlbmRhbGwgLSBtZWRlIGEgZm9yw6dhIGUgYSBkaXJlw6fDo28gZGEgcmVsYcOnw6NvIG1vbm90w7RuaWNhCmsgPC0gY29yKGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW9fYWxsJFRheGFfQVZDLCBtZXRob2QgPSAia2VuZGFsbCIpCnByaW50KGspCgpyZXN1bHRhZG8gPC0gY29yLnRlc3QoYXZjX2hpcGVydGVuc2FvX2FsbCRUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9BVkMsCiAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAia2VuZGFsbCIpCnByaW50KHJlc3VsdGFkbykKCiNleGlzdGUgdW1hIGNvcnJlbGHDp8OjbyBuZWdhdGl2YSBmcmFjYSAoLTAuMTU4OTI5OCkgZW50cmUgYXMgZHVhcyB2YXJpw6F2ZWlzCiMgMS43MmUtMDYgPCAwLDA1OiBBIGNvcnJlbGHDp8OjbyDDqSBlc3RhdGlzdGljYW1lbnRlIHNpZ25pZmljYXRpdmEsIGVtYm9yYSBmcmFjYS4KYGBgCgoKYGBge3J9CiNjb3JyZWxhw6fDo28gQVZDIGUgaGlwZXJ0ZW5zw6NvIFPDkyBub3MgYW5vcyBlbSBjb211bQoKCmF2Y19oaXBlcnRlbnNhbyA8LSBhdmNfcmVnaWFvICAlPiUKICBpbm5lcl9qb2luKGhpcGVydGVuc2FvX3RvdGFsLCBieSA9ICJEaXN0cml0byIpCgpnZ3Bsb3QoYXZjX2hpcGVydGVuc2FvLCBhZXMoeCA9IFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHkgPSBUb3RhbF9BVkMpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJzdGVlbGJsdWUiLCBzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkNvcnJlbGHDp8OjbyBlbnRyZSBIaXBlcnRlbnPDo28gQ29udHJvbGFkYSBlIFJlZ2lzdG9zIGRlIEFWQyBwb3IgRGlzdHJpdG8iLAogICAgICAgeCA9ICJUb3RhbCBkZSBIaXBlcnRlbnNvcyBDb250cm9sYWRvcyIsCiAgICAgICB5ID0gIlRvdGFsIGRlIFJlZ2lzdG9zIGRlIEFWQyIpICsKICB0aGVtZV9taW5pbWFsKCkKCmNvcnJlbGFjYW8gPC0gY29yKGF2Y19oaXBlcnRlbnNhbyRUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW8kVG90YWxfQVZDKQpwcmludChjb3JyZWxhY2FvKQpgYGAKYGBgCg==